/*!
 * jQuery JavaScript Library v1.6.2
 * http://jquery.com/
 *
 * Copyright 2011, John Resig
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * Includes Sizzle.js
 * http://sizzlejs.com/
 * Copyright 2011, The Dojo Foundation
 * Released under the MIT, BSD, and GPL Licenses.
 *
 * Date: Thu Jun 30 14:16:56 2011 -0400
 */
(function( window, undefined ) {

// Use the correct document accordingly with window argument (sandbox)
var document = window.document,
	navigator = window.navigator,
	location = window.location;
var jQuery = (function() {

// Define a local copy of jQuery
var jQuery = function( selector, context ) {
		// The jQuery object is actually just the init constructor 'enhanced'
		return new jQuery.fn.init( selector, context, rootjQuery );
	},

	// Map over jQuery in case of overwrite
	_jQuery = window.jQuery,

	// Map over the $ in case of overwrite
	_$ = window.$,

	// A central reference to the root jQuery(document)
	rootjQuery,

	// A simple way to check for HTML strings or ID strings
	// (both of which we optimize for)
	quickExpr = /^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,

	// Check if a string has a non-whitespace character in it
	rnotwhite = /\S/,

	// Used for trimming whitespace
	trimLeft = /^\s+/,
	trimRight = /\s+$/,

	// Check for digits
	rdigit = /\d/,

	// Match a standalone tag
	rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/,

	// JSON RegExp
	rvalidchars = /^[\],:{}\s]*$/,
	rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,
	rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
	rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,

	// Useragent RegExp
	rwebkit = /(webkit)[ \/]([\w.]+)/,
	ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/,
	rmsie = /(msie) ([\w.]+)/,
	rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/,

	// Matches dashed string for camelizing
	rdashAlpha = /-([a-z])/ig,

	// Used by jQuery.camelCase as callback to replace()
	fcamelCase = function( all, letter ) {
		return letter.toUpperCase();
	},

	// Keep a UserAgent string for use with jQuery.browser
	userAgent = navigator.userAgent,

	// For matching the engine and version of the browser
	browserMatch,

	// The deferred used on DOM ready
	readyList,

	// The ready event handler
	DOMContentLoaded,

	// Save a reference to some core methods
	toString = Object.prototype.toString,
	hasOwn = Object.prototype.hasOwnProperty,
	push = Array.prototype.push,
	slice = Array.prototype.slice,
	trim = String.prototype.trim,
	indexOf = Array.prototype.indexOf,

	// [[Class]] -> type pairs
	class2type = {};

jQuery.fn = jQuery.prototype = {
	constructor: jQuery,
	init: function( selector, context, rootjQuery ) {
		var match, elem, ret, doc;

		// Handle $(""), $(null), or $(undefined)
		if ( !selector ) {
			return this;
		}

		// Handle $(DOMElement)
		if ( selector.nodeType ) {
			this.context = this[0] = selector;
			this.length = 1;
			return this;
		}

		// The body element only exists once, optimize finding it
		if ( selector === "body" && !context && document.body ) {
			this.context = document;
			this[0] = document.body;
			this.selector = selector;
			this.length = 1;
			return this;
		}

		// Handle HTML strings
		if ( typeof selector === "string" ) {
			// Are we dealing with HTML string or an ID?
			if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
				// Assume that strings that start and end with <> are HTML and skip the regex check
				match = [ null, selector, null ];

			} else {
				match = quickExpr.exec( selector );
			}

			// Verify a match, and that no context was specified for #id
			if ( match && (match[1] || !context) ) {

				// HANDLE: $(html) -> $(array)
				if ( match[1] ) {
					context = context instanceof jQuery ? context[0] : context;
					doc = (context ? context.ownerDocument || context : document);

					// If a single string is passed in and it's a single tag
					// just do a createElement and skip the rest
					ret = rsingleTag.exec( selector );

					if ( ret ) {
						if ( jQuery.isPlainObject( context ) ) {
							selector = [ document.createElement( ret[1] ) ];
							jQuery.fn.attr.call( selector, context, true );

						} else {
							selector = [ doc.createElement( ret[1] ) ];
						}

					} else {
						ret = jQuery.buildFragment( [ match[1] ], [ doc ] );
						selector = (ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment).childNodes;
					}

					return jQuery.merge( this, selector );

				// HANDLE: $("#id")
				} else {
					elem = document.getElementById( match[2] );

					// Check parentNode to catch when Blackberry 4.6 returns
					// nodes that are no longer in the document #6963
					if ( elem && elem.parentNode ) {
						// Handle the case where IE and Opera return items
						// by name instead of ID
						if ( elem.id !== match[2] ) {
							return rootjQuery.find( selector );
						}

						// Otherwise, we inject the element directly into the jQuery object
						this.length = 1;
						this[0] = elem;
					}

					this.context = document;
					this.selector = selector;
					return this;
				}

			// HANDLE: $(expr, $(...))
			} else if ( !context || context.jquery ) {
				return (context || rootjQuery).find( selector );

			// HANDLE: $(expr, context)
			// (which is just equivalent to: $(context).find(expr)
			} else {
				return this.constructor( context ).find( selector );
			}

		// HANDLE: $(function)
		// Shortcut for document ready
		} else if ( jQuery.isFunction( selector ) ) {
			return rootjQuery.ready( selector );
		}

		if (selector.selector !== undefined) {
			this.selector = selector.selector;
			this.context = selector.context;
		}

		return jQuery.makeArray( selector, this );
	},

	// Start with an empty selector
	selector: "",

	// The current version of jQuery being used
	jquery: "1.6.2",

	// The default length of a jQuery object is 0
	length: 0,

	// The number of elements contained in the matched element set
	size: function() {
		return this.length;
	},

	toArray: function() {
		return slice.call( this, 0 );
	},

	// Get the Nth element in the matched element set OR
	// Get the whole matched element set as a clean array
	get: function( num ) {
		return num == null ?

			// Return a 'clean' array
			this.toArray() :

			// Return just the object
			( num < 0 ? this[ this.length + num ] : this[ num ] );
	},

	// Take an array of elements and push it onto the stack
	// (returning the new matched element set)
	pushStack: function( elems, name, selector ) {
		// Build a new jQuery matched element set
		var ret = this.constructor();

		if ( jQuery.isArray( elems ) ) {
			push.apply( ret, elems );

		} else {
			jQuery.merge( ret, elems );
		}

		// Add the old object onto the stack (as a reference)
		ret.prevObject = this;

		ret.context = this.context;

		if ( name === "find" ) {
			ret.selector = this.selector + (this.selector ? " " : "") + selector;
		} else if ( name ) {
			ret.selector = this.selector + "." + name + "(" + selector + ")";
		}

		// Return the newly-formed element set
		return ret;
	},

	// Execute a callback for every element in the matched set.
	// (You can seed the arguments with an array of args, but this is
	// only used internally.)
	each: function( callback, args ) {
		return jQuery.each( this, callback, args );
	},

	ready: function( fn ) {
		// Attach the listeners
		jQuery.bindReady();

		// Add the callback
		readyList.done( fn );

		return this;
	},

	eq: function( i ) {
		return i === -1 ?
			this.slice( i ) :
			this.slice( i, +i + 1 );
	},

	first: function() {
		return this.eq( 0 );
	},

	last: function() {
		return this.eq( -1 );
	},

	slice: function() {
		return this.pushStack( slice.apply( this, arguments ),
			"slice", slice.call(arguments).join(",") );
	},

	map: function( callback ) {
		return this.pushStack( jQuery.map(this, function( elem, i ) {
			return callback.call( elem, i, elem );
		}));
	},

	end: function() {
		return this.prevObject || this.constructor(null);
	},

	// For internal use only.
	// Behaves like an Array's method, not like a jQuery method.
	push: push,
	sort: [].sort,
	splice: [].splice
};

// Give the init function the jQuery prototype for later instantiation
jQuery.fn.init.prototype = jQuery.fn;

jQuery.extend = jQuery.fn.extend = function() {
	var options, name, src, copy, copyIsArray, clone,
		target = arguments[0] || {},
		i = 1,
		length = arguments.length,
		deep = false;

	// Handle a deep copy situation
	if ( typeof target === "boolean" ) {
		deep = target;
		target = arguments[1] || {};
		// skip the boolean and the target
		i = 2;
	}

	// Handle case when target is a string or something (possible in deep copy)
	if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
		target = {};
	}

	// extend jQuery itself if only one argument is passed
	if ( length === i ) {
		target = this;
		--i;
	}

	for ( ; i < length; i++ ) {
		// Only deal with non-null/undefined values
		if ( (options = arguments[ i ]) != null ) {
			// Extend the base object
			for ( name in options ) {
				src = target[ name ];
				copy = options[ name ];

				// Prevent never-ending loop
				if ( target === copy ) {
					continue;
				}

				// Recurse if we're merging plain objects or arrays
				if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
					if ( copyIsArray ) {
						copyIsArray = false;
						clone = src && jQuery.isArray(src) ? src : [];

					} else {
						clone = src && jQuery.isPlainObject(src) ? src : {};
					}

					// Never move original objects, clone them
					target[ name ] = jQuery.extend( deep, clone, copy );

				// Don't bring in undefined values
				} else if ( copy !== undefined ) {
					target[ name ] = copy;
				}
			}
		}
	}

	// Return the modified object
	return target;
};

jQuery.extend({
	noConflict: function( deep ) {
		if ( window.$ === jQuery ) {
			window.$ = _$;
		}

		if ( deep && window.jQuery === jQuery ) {
			window.jQuery = _jQuery;
		}

		return jQuery;
	},

	// Is the DOM ready to be used? Set to true once it occurs.
	isReady: false,

	// A counter to track how many items to wait for before
	// the ready event fires. See #6781
	readyWait: 1,

	// Hold (or release) the ready event
	holdReady: function( hold ) {
		if ( hold ) {
			jQuery.readyWait++;
		} else {
			jQuery.ready( true );
		}
	},

	// Handle when the DOM is ready
	ready: function( wait ) {
		// Either a released hold or an DOMready/load event and not yet ready
		if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) {
			// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
			if ( !document.body ) {
				return setTimeout( jQuery.ready, 1 );
			}

			// Remember that the DOM is ready
			jQuery.isReady = true;

			// If a normal DOM Ready event fired, decrement, and wait if need be
			if ( wait !== true && --jQuery.readyWait > 0 ) {
				return;
			}

			// If there are functions bound, to execute
			readyList.resolveWith( document, [ jQuery ] );

			// Trigger any bound ready events
			if ( jQuery.fn.trigger ) {
				jQuery( document ).trigger( "ready" ).unbind( "ready" );
			}
		}
	},

	bindReady: function() {
		if ( readyList ) {
			return;
		}

		readyList = jQuery._Deferred();

		// Catch cases where $(document).ready() is called after the
		// browser event has already occurred.
		if ( document.readyState === "complete" ) {
			// Handle it asynchronously to allow scripts the opportunity to delay ready
			return setTimeout( jQuery.ready, 1 );
		}

		// Mozilla, Opera and webkit nightlies currently support this event
		if ( document.addEventListener ) {
			// Use the handy event callback
			document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );

			// A fallback to window.onload, that will always work
			window.addEventListener( "load", jQuery.ready, false );

		// If IE event model is used
		} else if ( document.attachEvent ) {
			// ensure firing before onload,
			// maybe late but safe also for iframes
			document.attachEvent( "onreadystatechange", DOMContentLoaded );

			// A fallback to window.onload, that will always work
			window.attachEvent( "onload", jQuery.ready );

			// If IE and not a frame
			// continually check to see if the document is ready
			var toplevel = false;

			try {
				toplevel = window.frameElement == null;
			} catch(e) {}

			if ( document.documentElement.doScroll && toplevel ) {
				doScrollCheck();
			}
		}
	},

	// See test/unit/core.js for details concerning isFunction.
	// Since version 1.3, DOM methods and functions like alert
	// aren't supported. They return false on IE (#2968).
	isFunction: function( obj ) {
		return jQuery.type(obj) === "function";
	},

	isArray: Array.isArray || function( obj ) {
		return jQuery.type(obj) === "array";
	},

	// A crude way of determining if an object is a window
	isWindow: function( obj ) {
		return obj && typeof obj === "object" && "setInterval" in obj;
	},

	isNaN: function( obj ) {
		return obj == null || !rdigit.test( obj ) || isNaN( obj );
	},

	type: function( obj ) {
		return obj == null ?
			String( obj ) :
			class2type[ toString.call(obj) ] || "object";
	},

	isPlainObject: function( obj ) {
		// Must be an Object.
		// Because of IE, we also have to check the presence of the constructor property.
		// Make sure that DOM nodes and window objects don't pass through, as well
		if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
			return false;
		}

		// Not own constructor property must be Object
		if ( obj.constructor &&
			!hasOwn.call(obj, "constructor") &&
			!hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
			return false;
		}

		// Own properties are enumerated firstly, so to speed up,
		// if last one is own, then all properties are own.

		var key;
		for ( key in obj ) {}

		return key === undefined || hasOwn.call( obj, key );
	},

	isEmptyObject: function( obj ) {
		for ( var name in obj ) {
			return false;
		}
		return true;
	},

	error: function( msg ) {
		throw msg;
	},

	parseJSON: function( data ) {
		if ( typeof data !== "string" || !data ) {
			return null;
		}

		// Make sure leading/trailing whitespace is removed (IE can't handle it)
		data = jQuery.trim( data );

		// Attempt to parse using the native JSON parser first
		if ( window.JSON && window.JSON.parse ) {
			return window.JSON.parse( data );
		}

		// Make sure the incoming data is actual JSON
		// Logic borrowed from http://json.org/json2.js
		if ( rvalidchars.test( data.replace( rvalidescape, "@" )
			.replace( rvalidtokens, "]" )
			.replace( rvalidbraces, "")) ) {

			return (new Function( "return " + data ))();

		}
		jQuery.error( "Invalid JSON: " + data );
	},

	// Cross-browser xml parsing
	// (xml & tmp used internally)
	parseXML: function( data , xml , tmp ) {

		if ( window.DOMParser ) { // Standard
			tmp = new DOMParser();
			xml = tmp.parseFromString( data , "text/xml" );
		} else { // IE
			xml = new ActiveXObject( "Microsoft.XMLDOM" );
			xml.async = "false";
			xml.loadXML( data );
		}

		tmp = xml.documentElement;

		if ( ! tmp || ! tmp.nodeName || tmp.nodeName === "parsererror" ) {
			jQuery.error( "Invalid XML: " + data );
		}

		return xml;
	},

	noop: function() {},

	// Evaluates a script in a global context
	// Workarounds based on findings by Jim Driscoll
	// http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
	globalEval: function( data ) {
		if ( data && rnotwhite.test( data ) ) {
			// We use execScript on Internet Explorer
			// We use an anonymous function so that context is window
			// rather than jQuery in Firefox
			( window.execScript || function( data ) {
				window[ "eval" ].call( window, data );
			} )( data );
		}
	},

	// Converts a dashed string to camelCased string;
	// Used by both the css and data modules
	camelCase: function( string ) {
		return string.replace( rdashAlpha, fcamelCase );
	},

	nodeName: function( elem, name ) {
		return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase();
	},

	// args is for internal usage only
	each: function( object, callback, args ) {
		var name, i = 0,
			length = object.length,
			isObj = length === undefined || jQuery.isFunction( object );

		if ( args ) {
			if ( isObj ) {
				for ( name in object ) {
					if ( callback.apply( object[ name ], args ) === false ) {
						break;
					}
				}
			} else {
				for ( ; i < length; ) {
					if ( callback.apply( object[ i++ ], args ) === false ) {
						break;
					}
				}
			}

		// A special, fast, case for the most common use of each
		} else {
			if ( isObj ) {
				for ( name in object ) {
					if ( callback.call( object[ name ], name, object[ name ] ) === false ) {
						break;
					}
				}
			} else {
				for ( ; i < length; ) {
					if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) {
						break;
					}
				}
			}
		}

		return object;
	},

	// Use native String.trim function wherever possible
	trim: trim ?
		function( text ) {
			return text == null ?
				"" :
				trim.call( text );
		} :

		// Otherwise use our own trimming functionality
		function( text ) {
			return text == null ?
				"" :
				text.toString().replace( trimLeft, "" ).replace( trimRight, "" );
		},

	// results is for internal usage only
	makeArray: function( array, results ) {
		var ret = results || [];

		if ( array != null ) {
			// The window, strings (and functions) also have 'length'
			// The extra typeof function check is to prevent crashes
			// in Safari 2 (See: #3039)
			// Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930
			var type = jQuery.type( array );

			if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) {
				push.call( ret, array );
			} else {
				jQuery.merge( ret, array );
			}
		}

		return ret;
	},

	inArray: function( elem, array ) {

		if ( indexOf ) {
			return indexOf.call( array, elem );
		}

		for ( var i = 0, length = array.length; i < length; i++ ) {
			if ( array[ i ] === elem ) {
				return i;
			}
		}

		return -1;
	},

	merge: function( first, second ) {
		var i = first.length,
			j = 0;

		if ( typeof second.length === "number" ) {
			for ( var l = second.length; j < l; j++ ) {
				first[ i++ ] = second[ j ];
			}

		} else {
			while ( second[j] !== undefined ) {
				first[ i++ ] = second[ j++ ];
			}
		}

		first.length = i;

		return first;
	},

	grep: function( elems, callback, inv ) {
		var ret = [], retVal;
		inv = !!inv;

		// Go through the array, only saving the items
		// that pass the validator function
		for ( var i = 0, length = elems.length; i < length; i++ ) {
			retVal = !!callback( elems[ i ], i );
			if ( inv !== retVal ) {
				ret.push( elems[ i ] );
			}
		}

		return ret;
	},

	// arg is for internal usage only
	map: function( elems, callback, arg ) {
		var value, key, ret = [],
			i = 0,
			length = elems.length,
			// jquery objects are treated as arrays
			isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ;

		// Go through the array, translating each of the items to their
		if ( isArray ) {
			for ( ; i < length; i++ ) {
				value = callback( elems[ i ], i, arg );

				if ( value != null ) {
					ret[ ret.length ] = value;
				}
			}

		// Go through every key on the object,
		} else {
			for ( key in elems ) {
				value = callback( elems[ key ], key, arg );

				if ( value != null ) {
					ret[ ret.length ] = value;
				}
			}
		}

		// Flatten any nested arrays
		return ret.concat.apply( [], ret );
	},

	// A global GUID counter for objects
	guid: 1,

	// Bind a function to a context, optionally partially applying any
	// arguments.
	proxy: function( fn, context ) {
		if ( typeof context === "string" ) {
			var tmp = fn[ context ];
			context = fn;
			fn = tmp;
		}

		// Quick check to determine if target is callable, in the spec
		// this throws a TypeError, but we will just return undefined.
		if ( !jQuery.isFunction( fn ) ) {
			return undefined;
		}

		// Simulated bind
		var args = slice.call( arguments, 2 ),
			proxy = function() {
				return fn.apply( context, args.concat( slice.call( arguments ) ) );
			};

		// Set the guid of unique handler to the same of original handler, so it can be removed
		proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++;

		return proxy;
	},

	// Mutifunctional method to get and set values to a collection
	// The value/s can optionally be executed if it's a function
	access: function( elems, key, value, exec, fn, pass ) {
		var length = elems.length;

		// Setting many attributes
		if ( typeof key === "object" ) {
			for ( var k in key ) {
				jQuery.access( elems, k, key[k], exec, fn, value );
			}
			return elems;
		}

		// Setting one attribute
		if ( value !== undefined ) {
			// Optionally, function values get executed if exec is true
			exec = !pass && exec && jQuery.isFunction(value);

			for ( var i = 0; i < length; i++ ) {
				fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );
			}

			return elems;
		}

		// Getting an attribute
		return length ? fn( elems[0], key ) : undefined;
	},

	now: function() {
		return (new Date()).getTime();
	},

	// Use of jQuery.browser is frowned upon.
	// More details: http://docs.jquery.com/Utilities/jQuery.browser
	uaMatch: function( ua ) {
		ua = ua.toLowerCase();

		var match = rwebkit.exec( ua ) ||
			ropera.exec( ua ) ||
			rmsie.exec( ua ) ||
			ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) ||
			[];

		return { browser: match[1] || "", version: match[2] || "0" };
	},

	sub: function() {
		function jQuerySub( selector, context ) {
			return new jQuerySub.fn.init( selector, context );
		}
		jQuery.extend( true, jQuerySub, this );
		jQuerySub.superclass = this;
		jQuerySub.fn = jQuerySub.prototype = this();
		jQuerySub.fn.constructor = jQuerySub;
		jQuerySub.sub = this.sub;
		jQuerySub.fn.init = function init( selector, context ) {
			if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) {
				context = jQuerySub( context );
			}

			return jQuery.fn.init.call( this, selector, context, rootjQuerySub );
		};
		jQuerySub.fn.init.prototype = jQuerySub.fn;
		var rootjQuerySub = jQuerySub(document);
		return jQuerySub;
	},

	browser: {}
});

// Populate the class2type map
jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) {
	class2type[ "[object " + name + "]" ] = name.toLowerCase();
});

browserMatch = jQuery.uaMatch( userAgent );
if ( browserMatch.browser ) {
	jQuery.browser[ browserMatch.browser ] = true;
	jQuery.browser.version = browserMatch.version;
}

// Deprecated, use jQuery.browser.webkit instead
if ( jQuery.browser.webkit ) {
	jQuery.browser.safari = true;
}

// IE doesn't match non-breaking spaces with \s
if ( rnotwhite.test( "\xA0" ) ) {
	trimLeft = /^[\s\xA0]+/;
	trimRight = /[\s\xA0]+$/;
}

// All jQuery objects should point back to these
rootjQuery = jQuery(document);

// Cleanup functions for the document ready method
if ( document.addEventListener ) {
	DOMContentLoaded = function() {
		document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
		jQuery.ready();
	};

} else if ( document.attachEvent ) {
	DOMContentLoaded = function() {
		// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
		if ( document.readyState === "complete" ) {
			document.detachEvent( "onreadystatechange", DOMContentLoaded );
			jQuery.ready();
		}
	};
}

// The DOM ready check for Internet Explorer
function doScrollCheck() {
	if ( jQuery.isReady ) {
		return;
	}

	try {
		// If IE is used, use the trick by Diego Perini
		// http://javascript.nwbox.com/IEContentLoaded/
		document.documentElement.doScroll("left");
	} catch(e) {
		setTimeout( doScrollCheck, 1 );
		return;
	}

	// and execute any waiting functions
	jQuery.ready();
}

return jQuery;

})();


var // Promise methods
	promiseMethods = "done fail isResolved isRejected promise then always pipe".split( " " ),
	// Static reference to slice
	sliceDeferred = [].slice;

jQuery.extend({
	// Create a simple deferred (one callbacks list)
	_Deferred: function() {
		var // callbacks list
			callbacks = [],
			// stored [ context , args ]
			fired,
			// to avoid firing when already doing so
			firing,
			// flag to know if the deferred has been cancelled
			cancelled,
			// the deferred itself
			deferred  = {

				// done( f1, f2, ...)
				done: function() {
					if ( !cancelled ) {
						var args = arguments,
							i,
							length,
							elem,
							type,
							_fired;
						if ( fired ) {
							_fired = fired;
							fired = 0;
						}
						for ( i = 0, length = args.length; i < length; i++ ) {
							elem = args[ i ];
							type = jQuery.type( elem );
							if ( type === "array" ) {
								deferred.done.apply( deferred, elem );
							} else if ( type === "function" ) {
								callbacks.push( elem );
							}
						}
						if ( _fired ) {
							deferred.resolveWith( _fired[ 0 ], _fired[ 1 ] );
						}
					}
					return this;
				},

				// resolve with given context and args
				resolveWith: function( context, args ) {
					if ( !cancelled && !fired && !firing ) {
						// make sure args are available (#8421)
						args = args || [];
						firing = 1;
						
						try {
							while( callbacks[ 0 ] ) {
								callbacks.shift().apply( context, args );
							}
						}
						catch (err) {
							//alert(err+": "+args[0]);
						}
						finally {
							fired = [ context, args ];
							firing = 0;
						}
					}
					return this;
				},

				// resolve with this as context and given arguments
				resolve: function() {
					deferred.resolveWith( this, arguments );
					return this;
				},

				// Has this deferred been resolved?
				isResolved: function() {
					return !!( firing || fired );
				},

				// Cancel
				cancel: function() {
					cancelled = 1;
					callbacks = [];
					return this;
				}
			};

		return deferred;
	},

	// Full fledged deferred (two callbacks list)
	Deferred: function( func ) {
		var deferred = jQuery._Deferred(),
			failDeferred = jQuery._Deferred(),
			promise;
		// Add errorDeferred methods, then and promise
		jQuery.extend( deferred, {
			then: function( doneCallbacks, failCallbacks ) {
				deferred.done( doneCallbacks ).fail( failCallbacks );
				return this;
			},
			always: function() {
				return deferred.done.apply( deferred, arguments ).fail.apply( this, arguments );
			},
			fail: failDeferred.done,
			rejectWith: failDeferred.resolveWith,
			reject: failDeferred.resolve,
			isRejected: failDeferred.isResolved,
			pipe: function( fnDone, fnFail ) {
				return jQuery.Deferred(function( newDefer ) {
					jQuery.each( {
						done: [ fnDone, "resolve" ],
						fail: [ fnFail, "reject" ]
					}, function( handler, data ) {
						var fn = data[ 0 ],
							action = data[ 1 ],
							returned;
						if ( jQuery.isFunction( fn ) ) {
							deferred[ handler ](function() {
								returned = fn.apply( this, arguments );
								if ( returned && jQuery.isFunction( returned.promise ) ) {
									returned.promise().then( newDefer.resolve, newDefer.reject );
								} else {
									newDefer[ action ]( returned );
								}
							});
						} else {
							deferred[ handler ]( newDefer[ action ] );
						}
					});
				}).promise();
			},
			// Get a promise for this deferred
			// If obj is provided, the promise aspect is added to the object
			promise: function( obj ) {
				if ( obj == null ) {
					if ( promise ) {
						return promise;
					}
					promise = obj = {};
				}
				var i = promiseMethods.length;
				while( i-- ) {
					obj[ promiseMethods[i] ] = deferred[ promiseMethods[i] ];
				}
				return obj;
			}
		});
		// Make sure only one callback list will be used
		deferred.done( failDeferred.cancel ).fail( deferred.cancel );
		// Unexpose cancel
		delete deferred.cancel;
		// Call given func if any
		if ( func ) {
			func.call( deferred, deferred );
		}
		return deferred;
	},

	// Deferred helper
	when: function( firstParam ) {
		var args = arguments,
			i = 0,
			length = args.length,
			count = length,
			deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ?
				firstParam :
				jQuery.Deferred();
		function resolveFunc( i ) {
			return function( value ) {
				args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value;
				if ( !( --count ) ) {
					// Strange bug in FF4:
					// Values changed onto the arguments object sometimes end up as undefined values
					// outside the $.when method. Cloning the object into a fresh array solves the issue
					deferred.resolveWith( deferred, sliceDeferred.call( args, 0 ) );
				}
			};
		}
		if ( length > 1 ) {
			for( ; i < length; i++ ) {
				if ( args[ i ] && jQuery.isFunction( args[ i ].promise ) ) {
					args[ i ].promise().then( resolveFunc(i), deferred.reject );
				} else {
					--count;
				}
			}
			if ( !count ) {
				deferred.resolveWith( deferred, args );
			}
		} else if ( deferred !== firstParam ) {
			deferred.resolveWith( deferred, length ? [ firstParam ] : [] );
		}
		return deferred.promise();
	}
});



jQuery.support = (function() {

	var div = document.createElement( "div" ),
		documentElement = document.documentElement,
		all,
		a,
		select,
		opt,
		input,
		marginDiv,
		support,
		fragment,
		body,
		testElementParent,
		testElement,
		testElementStyle,
		tds,
		events,
		eventName,
		i,
		isSupported;

	// Preliminary tests
	div.setAttribute("className", "t");
	div.innerHTML = "   <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>";

	all = div.getElementsByTagName( "*" );
	a = div.getElementsByTagName( "a" )[ 0 ];

	// Can't get basic test support
	if ( !all || !all.length || !a ) {
		return {};
	}

	// First batch of supports tests
	select = document.createElement( "select" );
	opt = select.appendChild( document.createElement("option") );
	input = div.getElementsByTagName( "input" )[ 0 ];

	support = {
		// IE strips leading whitespace when .innerHTML is used
		leadingWhitespace: ( div.firstChild.nodeType === 3 ),

		// Make sure that tbody elements aren't automatically inserted
		// IE will insert them into empty tables
		tbody: !div.getElementsByTagName( "tbody" ).length,

		// Make sure that link elements get serialized correctly by innerHTML
		// This requires a wrapper element in IE
		htmlSerialize: !!div.getElementsByTagName( "link" ).length,

		// Get the style information from getAttribute
		// (IE uses .cssText instead)
		style: /top/.test( a.getAttribute("style") ),

		// Make sure that URLs aren't manipulated
		// (IE normalizes it by default)
		hrefNormalized: ( a.getAttribute( "href" ) === "/a" ),

		// Make sure that element opacity exists
		// (IE uses filter instead)
		// Use a regex to work around a WebKit issue. See #5145
		opacity: /^0.55$/.test( a.style.opacity ),

		// Verify style float existence
		// (IE uses styleFloat instead of cssFloat)
		cssFloat: !!a.style.cssFloat,

		// Make sure that if no value is specified for a checkbox
		// that it defaults to "on".
		// (WebKit defaults to "" instead)
		checkOn: ( input.value === "on" ),

		// Make sure that a selected-by-default option has a working selected property.
		// (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
		optSelected: opt.selected,

		// Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
		getSetAttribute: div.className !== "t",

		// Will be defined later
		submitBubbles: true,
		changeBubbles: true,
		focusinBubbles: false,
		deleteExpando: true,
		noCloneEvent: true,
		inlineBlockNeedsLayout: false,
		shrinkWrapBlocks: false,
		reliableMarginRight: true
	};

	// Make sure checked status is properly cloned
	input.checked = true;
	support.noCloneChecked = input.cloneNode( true ).checked;

	// Make sure that the options inside disabled selects aren't marked as disabled
	// (WebKit marks them as disabled)
	select.disabled = true;
	support.optDisabled = !opt.disabled;

	// Test to see if it's possible to delete an expando from an element
	// Fails in Internet Explorer
	try {
		delete div.test;
	} catch( e ) {
		support.deleteExpando = false;
	}

	if ( !div.addEventListener && div.attachEvent && div.fireEvent ) {
		div.attachEvent( "onclick", function() {
			// Cloning a node shouldn't copy over any
			// bound event handlers (IE does this)
			support.noCloneEvent = false;
		});
		div.cloneNode( true ).fireEvent( "onclick" );
	}

	// Check if a radio maintains it's value
	// after being appended to the DOM
	input = document.createElement("input");
	input.value = "t";
	input.setAttribute("type", "radio");
	support.radioValue = input.value === "t";

	input.setAttribute("checked", "checked");
	div.appendChild( input );
	fragment = document.createDocumentFragment();
	fragment.appendChild( div.firstChild );

	// WebKit doesn't clone checked state correctly in fragments
	support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;

	div.innerHTML = "";

	// Figure out if the W3C box model works as expected
	div.style.width = div.style.paddingLeft = "1px";

	body = document.getElementsByTagName( "body" )[ 0 ];
	// We use our own, invisible, body unless the body is already present
	// in which case we use a div (#9239)
	testElement = document.createElement( body ? "div" : "body" );
	testElementStyle = {
		visibility: "hidden",
		width: 0,
		height: 0,
		border: 0,
		margin: 0
	};
	if ( body ) {
		jQuery.extend( testElementStyle, {
			position: "absolute",
			left: -1000,
			top: -1000
		});
	}
	for ( i in testElementStyle ) {
		testElement.style[ i ] = testElementStyle[ i ];
	}
	testElement.appendChild( div );
	testElementParent = body || documentElement;
	testElementParent.insertBefore( testElement, testElementParent.firstChild );

	// Check if a disconnected checkbox will retain its checked
	// value of true after appended to the DOM (IE6/7)
	support.appendChecked = input.checked;

	support.boxModel = div.offsetWidth === 2;

	if ( "zoom" in div.style ) {
		// Check if natively block-level elements act like inline-block
		// elements when setting their display to 'inline' and giving
		// them layout
		// (IE < 8 does this)
		div.style.display = "inline";
		div.style.zoom = 1;
		support.inlineBlockNeedsLayout = ( div.offsetWidth === 2 );

		// Check if elements with layout shrink-wrap their children
		// (IE 6 does this)
		div.style.display = "";
		div.innerHTML = "<div style='width:4px;'></div>";
		support.shrinkWrapBlocks = ( div.offsetWidth !== 2 );
	}

	div.innerHTML = "<table><tr><td style='padding:0;border:0;display:none'></td><td>t</td></tr></table>";
	tds = div.getElementsByTagName( "td" );

	// Check if table cells still have offsetWidth/Height when they are set
	// to display:none and there are still other visible table cells in a
	// table row; if so, offsetWidth/Height are not reliable for use when
	// determining if an element has been hidden directly using
	// display:none (it is still safe to use offsets if a parent element is
	// hidden; don safety goggles and see bug #4512 for more information).
	// (only IE 8 fails this test)
	isSupported = ( tds[ 0 ].offsetHeight === 0 );

	tds[ 0 ].style.display = "";
	tds[ 1 ].style.display = "none";

	// Check if empty table cells still have offsetWidth/Height
	// (IE < 8 fail this test)
	support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );
	div.innerHTML = "";

	// Check if div with explicit width and no margin-right incorrectly
	// gets computed margin-right based on width of container. For more
	// info see bug #3333
	// Fails in WebKit before Feb 2011 nightlies
	// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
	if ( document.defaultView && document.defaultView.getComputedStyle ) {
		marginDiv = document.createElement( "div" );
		marginDiv.style.width = "0";
		marginDiv.style.marginRight = "0";
		div.appendChild( marginDiv );
		support.reliableMarginRight =
			( parseInt( ( document.defaultView.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0;
	}

	// Remove the body element we added
	testElement.innerHTML = "";
	testElementParent.removeChild( testElement );

	// Technique from Juriy Zaytsev
	// http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/
	// We only care about the case where non-standard event systems
	// are used, namely in IE. Short-circuiting here helps us to
	// avoid an eval call (in setAttribute) which can cause CSP
	// to go haywire. See: https://developer.mozilla.org/en/Security/CSP
	if ( div.attachEvent ) {
		for( i in {
			submit: 1,
			change: 1,
			focusin: 1
		} ) {
			eventName = "on" + i;
			isSupported = ( eventName in div );
			if ( !isSupported ) {
				div.setAttribute( eventName, "return;" );
				isSupported = ( typeof div[ eventName ] === "function" );
			}
			support[ i + "Bubbles" ] = isSupported;
		}
	}

	// Null connected elements to avoid leaks in IE
	testElement = fragment = select = opt = body = marginDiv = div = input = null;

	return support;
})();

// Keep track of boxModel
jQuery.boxModel = jQuery.support.boxModel;




var rbrace = /^(?:\{.*\}|\[.*\])$/,
	rmultiDash = /([a-z])([A-Z])/g;

jQuery.extend({
	cache: {},

	// Please use with caution
	uuid: 0,

	// Unique for each copy of jQuery on the page
	// Non-digits removed to match rinlinejQuery
	expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ),

	// The following elements throw uncatchable exceptions if you
	// attempt to add expando properties to them.
	noData: {
		"embed": true,
		// Ban all objects except for Flash (which handle expandos)
		"object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",
		"applet": true
	},

	hasData: function( elem ) {
		elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];

		return !!elem && !isEmptyDataObject( elem );
	},

	data: function( elem, name, data, pvt /* Internal Use Only */ ) {
		if ( !jQuery.acceptData( elem ) ) {
			return;
		}

		var internalKey = jQuery.expando, getByName = typeof name === "string", thisCache,

			// We have to handle DOM nodes and JS objects differently because IE6-7
			// can't GC object references properly across the DOM-JS boundary
			isNode = elem.nodeType,

			// Only DOM nodes need the global jQuery cache; JS object data is
			// attached directly to the object so GC can occur automatically
			cache = isNode ? jQuery.cache : elem,

			// Only defining an ID for JS objects if its cache already exists allows
			// the code to shortcut on the same path as a DOM node with no cache
			id = isNode ? elem[ jQuery.expando ] : elem[ jQuery.expando ] && jQuery.expando;

		// Avoid doing any more work than we need to when trying to get data on an
		// object that has no data at all
		if ( (!id || (pvt && id && !cache[ id ][ internalKey ])) && getByName && data === undefined ) {
			return;
		}

		if ( !id ) {
			// Only DOM nodes need a new unique ID for each element since their data
			// ends up in the global cache
			if ( isNode ) {
				elem[ jQuery.expando ] = id = ++jQuery.uuid;
			} else {
				id = jQuery.expando;
			}
		}

		if ( !cache[ id ] ) {
			cache[ id ] = {};

			// TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery
			// metadata on plain JS objects when the object is serialized using
			// JSON.stringify
			if ( !isNode ) {
				cache[ id ].toJSON = jQuery.noop;
			}
		}

		// An object can be passed to jQuery.data instead of a key/value pair; this gets
		// shallow copied over onto the existing cache
		if ( typeof name === "object" || typeof name === "function" ) {
			if ( pvt ) {
				cache[ id ][ internalKey ] = jQuery.extend(cache[ id ][ internalKey ], name);
			} else {
				cache[ id ] = jQuery.extend(cache[ id ], name);
			}
		}

		thisCache = cache[ id ];

		// Internal jQuery data is stored in a separate object inside the object's data
		// cache in order to avoid key collisions between internal data and user-defined
		// data
		if ( pvt ) {
			if ( !thisCache[ internalKey ] ) {
				thisCache[ internalKey ] = {};
			}

			thisCache = thisCache[ internalKey ];
		}

		if ( data !== undefined ) {
			thisCache[ jQuery.camelCase( name ) ] = data;
		}

		// TODO: This is a hack for 1.5 ONLY. It will be removed in 1.6. Users should
		// not attempt to inspect the internal events object using jQuery.data, as this
		// internal data object is undocumented and subject to change.
		if ( name === "events" && !thisCache[name] ) {
			return thisCache[ internalKey ] && thisCache[ internalKey ].events;
		}

		return getByName ? 
			// Check for both converted-to-camel and non-converted data property names
			thisCache[ jQuery.camelCase( name ) ] || thisCache[ name ] :
			thisCache;
	},

	removeData: function( elem, name, pvt /* Internal Use Only */ ) {
		if ( !jQuery.acceptData( elem ) ) {
			return;
		}

		var internalKey = jQuery.expando, isNode = elem.nodeType,

			// See jQuery.data for more information
			cache = isNode ? jQuery.cache : elem,

			// See jQuery.data for more information
			id = isNode ? elem[ jQuery.expando ] : jQuery.expando;

		// If there is already no cache entry for this object, there is no
		// purpose in continuing
		if ( !cache[ id ] ) {
			return;
		}

		if ( name ) {
			var thisCache = pvt ? cache[ id ][ internalKey ] : cache[ id ];

			if ( thisCache ) {
				delete thisCache[ name ];

				// If there is no data left in the cache, we want to continue
				// and let the cache object itself get destroyed
				if ( !isEmptyDataObject(thisCache) ) {
					return;
				}
			}
		}

		// See jQuery.data for more information
		if ( pvt ) {
			delete cache[ id ][ internalKey ];

			// Don't destroy the parent cache unless the internal data object
			// had been the only thing left in it
			if ( !isEmptyDataObject(cache[ id ]) ) {
				return;
			}
		}

		var internalCache = cache[ id ][ internalKey ];

		// Browsers that fail expando deletion also refuse to delete expandos on
		// the window, but it will allow it on all other JS objects; other browsers
		// don't care
		if ( jQuery.support.deleteExpando || cache != window ) {
			delete cache[ id ];
		} else {
			cache[ id ] = null;
		}

		// We destroyed the entire user cache at once because it's faster than
		// iterating through each key, but we need to continue to persist internal
		// data if it existed
		if ( internalCache ) {
			cache[ id ] = {};
			// TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery
			// metadata on plain JS objects when the object is serialized using
			// JSON.stringify
			if ( !isNode ) {
				cache[ id ].toJSON = jQuery.noop;
			}

			cache[ id ][ internalKey ] = internalCache;

		// Otherwise, we need to eliminate the expando on the node to avoid
		// false lookups in the cache for entries that no longer exist
		} else if ( isNode ) {
			// IE does not allow us to delete expando properties from nodes,
			// nor does it have a removeAttribute function on Document nodes;
			// we must handle all of these cases
			if ( jQuery.support.deleteExpando ) {
				delete elem[ jQuery.expando ];
			} else if ( elem.removeAttribute ) {
				elem.removeAttribute( jQuery.expando );
			} else {
				elem[ jQuery.expando ] = null;
			}
		}
	},

	// For internal use only.
	_data: function( elem, name, data ) {
		return jQuery.data( elem, name, data, true );
	},

	// A method for determining if a DOM node can handle the data expando
	acceptData: function( elem ) {
		if ( elem.nodeName ) {
			var match = jQuery.noData[ elem.nodeName.toLowerCase() ];

			if ( match ) {
				return !(match === true || elem.getAttribute("classid") !== match);
			}
		}

		return true;
	}
});

jQuery.fn.extend({
	data: function( key, value ) {
		var data = null;

		if ( typeof key === "undefined" ) {
			if ( this.length ) {
				data = jQuery.data( this[0] );

				if ( this[0].nodeType === 1 ) {
			    var attr = this[0].attributes, name;
					for ( var i = 0, l = attr.length; i < l; i++ ) {
						name = attr[i].name;

						if ( name.indexOf( "data-" ) === 0 ) {
							name = jQuery.camelCase( name.substring(5) );

							dataAttr( this[0], name, data[ name ] );
						}
					}
				}
			}

			return data;

		} else if ( typeof key === "object" ) {
			return this.each(function() {
				jQuery.data( this, key );
			});
		}

		var parts = key.split(".");
		parts[1] = parts[1] ? "." + parts[1] : "";

		if ( value === undefined ) {
			data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);

			// Try to fetch any internally stored data first
			if ( data === undefined && this.length ) {
				data = jQuery.data( this[0], key );
				data = dataAttr( this[0], key, data );
			}

			return data === undefined && parts[1] ?
				this.data( parts[0] ) :
				data;

		} else {
			return this.each(function() {
				var $this = jQuery( this ),
					args = [ parts[0], value ];

				$this.triggerHandler( "setData" + parts[1] + "!", args );
				jQuery.data( this, key, value );
				$this.triggerHandler( "changeData" + parts[1] + "!", args );
			});
		}
	},

	removeData: function( key ) {
		return this.each(function() {
			jQuery.removeData( this, key );
		});
	}
});

function dataAttr( elem, key, data ) {
	// If nothing was found internally, try to fetch any
	// data from the HTML5 data-* attribute
	if ( data === undefined && elem.nodeType === 1 ) {
		var name = "data-" + key.replace( rmultiDash, "$1-$2" ).toLowerCase();

		data = elem.getAttribute( name );

		if ( typeof data === "string" ) {
			try {
				data = data === "true" ? true :
				data === "false" ? false :
				data === "null" ? null :
				!jQuery.isNaN( data ) ? parseFloat( data ) :
					rbrace.test( data ) ? jQuery.parseJSON( data ) :
					data;
			} catch( e ) {}

			// Make sure we set the data so it isn't changed later
			jQuery.data( elem, key, data );

		} else {
			data = undefined;
		}
	}

	return data;
}

// TODO: This is a hack for 1.5 ONLY to allow objects with a single toJSON
// property to be considered empty objects; this property always exists in
// order to make sure JSON.stringify does not expose internal metadata
function isEmptyDataObject( obj ) {
	for ( var name in obj ) {
		if ( name !== "toJSON" ) {
			return false;
		}
	}

	return true;
}




function handleQueueMarkDefer( elem, type, src ) {
	var deferDataKey = type + "defer",
		queueDataKey = type + "queue",
		markDataKey = type + "mark",
		defer = jQuery.data( elem, deferDataKey, undefined, true );
	if ( defer &&
		( src === "queue" || !jQuery.data( elem, queueDataKey, undefined, true ) ) &&
		( src === "mark" || !jQuery.data( elem, markDataKey, undefined, true ) ) ) {
		// Give room for hard-coded callbacks to fire first
		// and eventually mark/queue something else on the element
		setTimeout( function() {
			if ( !jQuery.data( elem, queueDataKey, undefined, true ) &&
				!jQuery.data( elem, markDataKey, undefined, true ) ) {
				jQuery.removeData( elem, deferDataKey, true );
				defer.resolve();
			}
		}, 0 );
	}
}

jQuery.extend({

	_mark: function( elem, type ) {
		if ( elem ) {
			type = (type || "fx") + "mark";
			jQuery.data( elem, type, (jQuery.data(elem,type,undefined,true) || 0) + 1, true );
		}
	},

	_unmark: function( force, elem, type ) {
		if ( force !== true ) {
			type = elem;
			elem = force;
			force = false;
		}
		if ( elem ) {
			type = type || "fx";
			var key = type + "mark",
				count = force ? 0 : ( (jQuery.data( elem, key, undefined, true) || 1 ) - 1 );
			if ( count ) {
				jQuery.data( elem, key, count, true );
			} else {
				jQuery.removeData( elem, key, true );
				handleQueueMarkDefer( elem, type, "mark" );
			}
		}
	},

	queue: function( elem, type, data ) {
		if ( elem ) {
			type = (type || "fx") + "queue";
			var q = jQuery.data( elem, type, undefined, true );
			// Speed up dequeue by getting out quickly if this is just a lookup
			if ( data ) {
				if ( !q || jQuery.isArray(data) ) {
					q = jQuery.data( elem, type, jQuery.makeArray(data), true );
				} else {
					q.push( data );
				}
			}
			return q || [];
		}
	},

	dequeue: function( elem, type ) {
		type = type || "fx";

		var queue = jQuery.queue( elem, type ),
			fn = queue.shift(),
			defer;

		// If the fx queue is dequeued, always remove the progress sentinel
		if ( fn === "inprogress" ) {
			fn = queue.shift();
		}

		if ( fn ) {
			// Add a progress sentinel to prevent the fx queue from being
			// automatically dequeued
			if ( type === "fx" ) {
				queue.unshift("inprogress");
			}

			fn.call(elem, function() {
				jQuery.dequeue(elem, type);
			});
		}

		if ( !queue.length ) {
			jQuery.removeData( elem, type + "queue", true );
			handleQueueMarkDefer( elem, type, "queue" );
		}
	}
});

jQuery.fn.extend({
	queue: function( type, data ) {
		if ( typeof type !== "string" ) {
			data = type;
			type = "fx";
		}

		if ( data === undefined ) {
			return jQuery.queue( this[0], type );
		}
		return this.each(function() {
			var queue = jQuery.queue( this, type, data );

			if ( type === "fx" && queue[0] !== "inprogress" ) {
				jQuery.dequeue( this, type );
			}
		});
	},
	dequeue: function( type ) {
		return this.each(function() {
			jQuery.dequeue( this, type );
		});
	},
	// Based off of the plugin by Clint Helfers, with permission.
	// http://blindsignals.com/index.php/2009/07/jquery-delay/
	delay: function( time, type ) {
		time = jQuery.fx ? jQuery.fx.speeds[time] || time : time;
		type = type || "fx";

		return this.queue( type, function() {
			var elem = this;
			setTimeout(function() {
				jQuery.dequeue( elem, type );
			}, time );
		});
	},
	clearQueue: function( type ) {
		return this.queue( type || "fx", [] );
	},
	// Get a promise resolved when queues of a certain type
	// are emptied (fx is the type by default)
	promise: function( type, object ) {
		if ( typeof type !== "string" ) {
			object = type;
			type = undefined;
		}
		type = type || "fx";
		var defer = jQuery.Deferred(),
			elements = this,
			i = elements.length,
			count = 1,
			deferDataKey = type + "defer",
			queueDataKey = type + "queue",
			markDataKey = type + "mark",
			tmp;
		function resolve() {
			if ( !( --count ) ) {
				defer.resolveWith( elements, [ elements ] );
			}
		}
		while( i-- ) {
			if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) ||
					( jQuery.data( elements[ i ], queueDataKey, undefined, true ) ||
						jQuery.data( elements[ i ], markDataKey, undefined, true ) ) &&
					jQuery.data( elements[ i ], deferDataKey, jQuery._Deferred(), true ) )) {
				count++;
				tmp.done( resolve );
			}
		}
		resolve();
		return defer.promise();
	}
});




var rclass = /[\n\t\r]/g,
	rspace = /\s+/,
	rreturn = /\r/g,
	rtype = /^(?:button|input)$/i,
	rfocusable = /^(?:button|input|object|select|textarea)$/i,
	rclickable = /^a(?:rea)?$/i,
	rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,
	rinvalidChar = /\:|^on/,
	formHook, boolHook;

jQuery.fn.extend({
	attr: function( name, value ) {
		return jQuery.access( this, name, value, true, jQuery.attr );
	},

	removeAttr: function( name ) {
		return this.each(function() {
			jQuery.removeAttr( this, name );
		});
	},
	
	prop: function( name, value ) {
		return jQuery.access( this, name, value, true, jQuery.prop );
	},
	
	removeProp: function( name ) {
		name = jQuery.propFix[ name ] || name;
		return this.each(function() {
			// try/catch handles cases where IE balks (such as removing a property on window)
			try {
				this[ name ] = undefined;
				delete this[ name ];
			} catch( e ) {}
		});
	},

	addClass: function( value ) {
		var classNames, i, l, elem,
			setClass, c, cl;

		if ( jQuery.isFunction( value ) ) {
			return this.each(function( j ) {
				jQuery( this ).addClass( value.call(this, j, this.className) );
			});
		}

		if ( value && typeof value === "string" ) {
			classNames = value.split( rspace );

			for ( i = 0, l = this.length; i < l; i++ ) {
				elem = this[ i ];

				if ( elem.nodeType === 1 ) {
					if ( !elem.className && classNames.length === 1 ) {
						elem.className = value;

					} else {
						setClass = " " + elem.className + " ";

						for ( c = 0, cl = classNames.length; c < cl; c++ ) {
							if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) {
								setClass += classNames[ c ] + " ";
							}
						}
						elem.className = jQuery.trim( setClass );
					}
				}
			}
		}

		return this;
	},

	removeClass: function( value ) {
		var classNames, i, l, elem, className, c, cl;

		if ( jQuery.isFunction( value ) ) {
			return this.each(function( j ) {
				jQuery( this ).removeClass( value.call(this, j, this.className) );
			});
		}

		if ( (value && typeof value === "string") || value === undefined ) {
			classNames = (value || "").split( rspace );

			for ( i = 0, l = this.length; i < l; i++ ) {
				elem = this[ i ];

				if ( elem.nodeType === 1 && elem.className ) {
					if ( value ) {
						className = (" " + elem.className + " ").replace( rclass, " " );
						for ( c = 0, cl = classNames.length; c < cl; c++ ) {
							className = className.replace(" " + classNames[ c ] + " ", " ");
						}
						elem.className = jQuery.trim( className );

					} else {
						elem.className = "";
					}
				}
			}
		}

		return this;
	},

	toggleClass: function( value, stateVal ) {
		var type = typeof value,
			isBool = typeof stateVal === "boolean";

		if ( jQuery.isFunction( value ) ) {
			return this.each(function( i ) {
				jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
			});
		}

		return this.each(function() {
			if ( type === "string" ) {
				// toggle individual class names
				var className,
					i = 0,
					self = jQuery( this ),
					state = stateVal,
					classNames = value.split( rspace );

				while ( (className = classNames[ i++ ]) ) {
					// check each className given, space seperated list
					state = isBool ? state : !self.hasClass( className );
					self[ state ? "addClass" : "removeClass" ]( className );
				}

			} else if ( type === "undefined" || type === "boolean" ) {
				if ( this.className ) {
					// store className if set
					jQuery._data( this, "__className__", this.className );
				}

				// toggle whole className
				this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
			}
		});
	},

	hasClass: function( selector ) {
		var className = " " + selector + " ";
		for ( var i = 0, l = this.length; i < l; i++ ) {
			if ( (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) {
				return true;
			}
		}

		return false;
	},

	val: function( value ) {
		var hooks, ret,
			elem = this[0];
		
		if ( !arguments.length ) {
			if ( elem ) {
				hooks = jQuery.valHooks[ elem.nodeName.toLowerCase() ] || jQuery.valHooks[ elem.type ];

				if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
					return ret;
				}

				ret = elem.value;

				return typeof ret === "string" ? 
					// handle most common string cases
					ret.replace(rreturn, "") : 
					// handle cases where value is null/undef or number
					ret == null ? "" : ret;
			}

			return undefined;
		}

		var isFunction = jQuery.isFunction( value );

		return this.each(function( i ) {
			var self = jQuery(this), val;

			if ( this.nodeType !== 1 ) {
				return;
			}

			if ( isFunction ) {
				val = value.call( this, i, self.val() );
			} else {
				val = value;
			}

			// Treat null/undefined as ""; convert numbers to string
			if ( val == null ) {
				val = "";
			} else if ( typeof val === "number" ) {
				val += "";
			} else if ( jQuery.isArray( val ) ) {
				val = jQuery.map(val, function ( value ) {
					return value == null ? "" : value + "";
				});
			}

			hooks = jQuery.valHooks[ this.nodeName.toLowerCase() ] || jQuery.valHooks[ this.type ];

			// If set returns undefined, fall back to normal setting
			if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
				this.value = val;
			}
		});
	}
});

jQuery.extend({
	valHooks: {
		option: {
			get: function( elem ) {
				// attributes.value is undefined in Blackberry 4.7 but
				// uses .value. See #6932
				var val = elem.attributes.value;
				return !val || val.specified ? elem.value : elem.text;
			}
		},
		select: {
			get: function( elem ) {
				var value,
					index = elem.selectedIndex,
					values = [],
					options = elem.options,
					one = elem.type === "select-one";

				// Nothing was selected
				if ( index < 0 ) {
					return null;
				}

				// Loop through all the selected options
				for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) {
					var option = options[ i ];

					// Don't return options that are disabled or in a disabled optgroup
					if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) &&
							(!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) {

						// Get the specific value for the option
						value = jQuery( option ).val();

						// We don't need an array for one selects
						if ( one ) {
							return value;
						}

						// Multi-Selects return an array
						values.push( value );
					}
				}

				// Fixes Bug #2551 -- select.val() broken in IE after form.reset()
				if ( one && !values.length && options.length ) {
					return jQuery( options[ index ] ).val();
				}

				return values;
			},

			set: function( elem, value ) {
				var values = jQuery.makeArray( value );

				jQuery(elem).find("option").each(function() {
					this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;
				});

				if ( !values.length ) {
					elem.selectedIndex = -1;
				}
				return values;
			}
		}
	},

	attrFn: {
		val: true,
		css: true,
		html: true,
		text: true,
		data: true,
		width: true,
		height: true,
		offset: true
	},
	
	attrFix: {
		// Always normalize to ensure hook usage
		tabindex: "tabIndex"
	},
	
	attr: function( elem, name, value, pass ) {
		var nType = elem.nodeType;
		
		// don't get/set attributes on text, comment and attribute nodes
		if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
			return undefined;
		}

		if ( pass && name in jQuery.attrFn ) {
			return jQuery( elem )[ name ]( value );
		}

		// Fallback to prop when attributes are not supported
		if ( !("getAttribute" in elem) ) {
			return jQuery.prop( elem, name, value );
		}

		var ret, hooks,
			notxml = nType !== 1 || !jQuery.isXMLDoc( elem );

		// Normalize the name if needed
		if ( notxml ) {
			name = jQuery.attrFix[ name ] || name;

			hooks = jQuery.attrHooks[ name ];

			if ( !hooks ) {
				// Use boolHook for boolean attributes
				if ( rboolean.test( name ) ) {

					hooks = boolHook;

				// Use formHook for forms and if the name contains certain characters
				} else if ( formHook && name !== "className" &&
					(jQuery.nodeName( elem, "form" ) || rinvalidChar.test( name )) ) {

					hooks = formHook;
				}
			}
		}

		if ( value !== undefined ) {

			if ( value === null ) {
				jQuery.removeAttr( elem, name );
				return undefined;

			} else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) {
				return ret;

			} else {
				elem.setAttribute( name, "" + value );
				return value;
			}

		} else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) {
			return ret;

		} else {

			ret = elem.getAttribute( name );

			// Non-existent attributes return null, we normalize to undefined
			return ret === null ?
				undefined :
				ret;
		}
	},

	removeAttr: function( elem, name ) {
		var propName;
		if ( elem.nodeType === 1 ) {
			name = jQuery.attrFix[ name ] || name;
		
			if ( jQuery.support.getSetAttribute ) {
				// Use removeAttribute in browsers that support it
				elem.removeAttribute( name );
			} else {
				jQuery.attr( elem, name, "" );
				elem.removeAttributeNode( elem.getAttributeNode( name ) );
			}

			// Set corresponding property to false for boolean attributes
			if ( rboolean.test( name ) && (propName = jQuery.propFix[ name ] || name) in elem ) {
				elem[ propName ] = false;
			}
		}
	},

	attrHooks: {
		type: {
			set: function( elem, value ) {
				// We can't allow the type property to be changed (since it causes problems in IE)
				if ( rtype.test( elem.nodeName ) && elem.parentNode ) {
					jQuery.error( "type property can't be changed" );
				} else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
					// Setting the type on a radio button after the value resets the value in IE6-9
					// Reset value to it's default in case type is set after value
					// This is for element creation
					var val = elem.value;
					elem.setAttribute( "type", value );
					if ( val ) {
						elem.value = val;
					}
					return value;
				}
			}
		},
		tabIndex: {
			get: function( elem ) {
				// elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
				// http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
				var attributeNode = elem.getAttributeNode("tabIndex");

				return attributeNode && attributeNode.specified ?
					parseInt( attributeNode.value, 10 ) :
					rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
						0 :
						undefined;
			}
		},
		// Use the value property for back compat
		// Use the formHook for button elements in IE6/7 (#1954)
		value: {
			get: function( elem, name ) {
				if ( formHook && jQuery.nodeName( elem, "button" ) ) {
					return formHook.get( elem, name );
				}
				return name in elem ?
					elem.value :
					null;
			},
			set: function( elem, value, name ) {
				if ( formHook && jQuery.nodeName( elem, "button" ) ) {
					return formHook.set( elem, value, name );
				}
				// Does not return so that setAttribute is also used
				elem.value = value;
			}
		}
	},

	propFix: {
		tabindex: "tabIndex",
		readonly: "readOnly",
		"for": "htmlFor",
		"class": "className",
		maxlength: "maxLength",
		cellspacing: "cellSpacing",
		cellpadding: "cellPadding",
		rowspan: "rowSpan",
		colspan: "colSpan",
		usemap: "useMap",
		frameborder: "frameBorder",
		contenteditable: "contentEditable"
	},
	
	prop: function( elem, name, value ) {
		var nType = elem.nodeType;

		// don't get/set properties on text, comment and attribute nodes
		if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
			return undefined;
		}

		var ret, hooks,
			notxml = nType !== 1 || !jQuery.isXMLDoc( elem );

		if ( notxml ) {
			// Fix name and attach hooks
			name = jQuery.propFix[ name ] || name;
			hooks = jQuery.propHooks[ name ];
		}

		if ( value !== undefined ) {
			if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
				return ret;

			} else {
				return (elem[ name ] = value);
			}

		} else {
			if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== undefined ) {
				return ret;

			} else {
				return elem[ name ];
			}
		}
	},
	
	propHooks: {}
});

// Hook for boolean attributes
boolHook = {
	get: function( elem, name ) {
		// Align boolean attributes with corresponding properties
		return jQuery.prop( elem, name ) ?
			name.toLowerCase() :
			undefined;
	},
	set: function( elem, value, name ) {
		var propName;
		if ( value === false ) {
			// Remove boolean attributes when set to false
			jQuery.removeAttr( elem, name );
		} else {
			// value is true since we know at this point it's type boolean and not false
			// Set boolean attributes to the same name and set the DOM property
			propName = jQuery.propFix[ name ] || name;
			if ( propName in elem ) {
				// Only set the IDL specifically if it already exists on the element
				elem[ propName ] = true;
			}

			elem.setAttribute( name, name.toLowerCase() );
		}
		return name;
	}
};

// IE6/7 do not support getting/setting some attributes with get/setAttribute
if ( !jQuery.support.getSetAttribute ) {

	// propFix is more comprehensive and contains all fixes
	jQuery.attrFix = jQuery.propFix;
	
	// Use this for any attribute on a form in IE6/7
	formHook = jQuery.attrHooks.name = jQuery.attrHooks.title = jQuery.valHooks.button = {
		get: function( elem, name ) {
			var ret;
			ret = elem.getAttributeNode( name );
			// Return undefined if nodeValue is empty string
			return ret && ret.nodeValue !== "" ?
				ret.nodeValue :
				undefined;
		},
		set: function( elem, value, name ) {
			// Check form objects in IE (multiple bugs related)
			// Only use nodeValue if the attribute node exists on the form
			var ret = elem.getAttributeNode( name );
			if ( ret ) {
				ret.nodeValue = value;
				return value;
			}
		}
	};

	// Set width and height to auto instead of 0 on empty string( Bug #8150 )
	// This is for removals
	jQuery.each([ "width", "height" ], function( i, name ) {
		jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
			set: function( elem, value ) {
				if ( value === "" ) {
					elem.setAttribute( name, "auto" );
					return value;
				}
			}
		});
	});
}


// Some attributes require a special call on IE
if ( !jQuery.support.hrefNormalized ) {
	jQuery.each([ "href", "src", "width", "height" ], function( i, name ) {
		jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
			get: function( elem ) {
				var ret = elem.getAttribute( name, 2 );
				return ret === null ? undefined : ret;
			}
		});
	});
}

if ( !jQuery.support.style ) {
	jQuery.attrHooks.style = {
		get: function( elem ) {
			// Return undefined in the case of empty string
			// Normalize to lowercase since IE uppercases css property names
			return elem.style.cssText.toLowerCase() || undefined;
		},
		set: function( elem, value ) {
			return (elem.style.cssText = "" + value);
		}
	};
}

// Safari mis-reports the default selected property of an option
// Accessing the parent's selectedIndex property fixes it
if ( !jQuery.support.optSelected ) {
	jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, {
		get: function( elem ) {
			var parent = elem.parentNode;

			if ( parent ) {
				parent.selectedIndex;

				// Make sure that it also works with optgroups, see #5701
				if ( parent.parentNode ) {
					parent.parentNode.selectedIndex;
				}
			}
		}
	});
}

// Radios and checkboxes getter/setter
if ( !jQuery.support.checkOn ) {
	jQuery.each([ "radio", "checkbox" ], function() {
		jQuery.valHooks[ this ] = {
			get: function( elem ) {
				// Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified
				return elem.getAttribute("value") === null ? "on" : elem.value;
			}
		};
	});
}
jQuery.each([ "radio", "checkbox" ], function() {
	jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], {
		set: function( elem, value ) {
			if ( jQuery.isArray( value ) ) {
				return (elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0);
			}
		}
	});
});




var rnamespaces = /\.(.*)$/,
	rformElems = /^(?:textarea|input|select)$/i,
	rperiod = /\./g,
	rspaces = / /g,
	rescape = /[^\w\s.|`]/g,
	fcleanup = function( nm ) {
		return nm.replace(rescape, "\\$&");
	};

/*
 * A number of helper functions used for managing events.
 * Many of the ideas behind this code originated from
 * Dean Edwards' addEvent library.
 */
jQuery.event = {

	// Bind an event to an element
	// Original by Dean Edwards
	add: function( elem, types, handler, data ) {
		if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
			return;
		}

		if ( handler === false ) {
			handler = returnFalse;
		} else if ( !handler ) {
			// Fixes bug #7229. Fix recommended by jdalton
			return;
		}

		var handleObjIn, handleObj;

		if ( handler.handler ) {
			handleObjIn = handler;
			handler = handleObjIn.handler;
		}

		// Make sure that the function being executed has a unique ID
		if ( !handler.guid ) {
			handler.guid = jQuery.guid++;
		}

		// Init the element's event structure
		var elemData = jQuery._data( elem );

		// If no elemData is found then we must be trying to bind to one of the
		// banned noData elements
		if ( !elemData ) {
			return;
		}

		var events = elemData.events,
			eventHandle = elemData.handle;

		if ( !events ) {
			elemData.events = events = {};
		}

		if ( !eventHandle ) {
			elemData.handle = eventHandle = function( e ) {
				// Discard the second event of a jQuery.event.trigger() and
				// when an event is called after a page has unloaded
				return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ?
					jQuery.event.handle.apply( eventHandle.elem, arguments ) :
					undefined;
			};
		}

		// Add elem as a property of the handle function
		// This is to prevent a memory leak with non-native events in IE.
		eventHandle.elem = elem;

		// Handle multiple events separated by a space
		// jQuery(...).bind("mouseover mouseout", fn);
		types = types.split(" ");

		var type, i = 0, namespaces;

		while ( (type = types[ i++ ]) ) {
			handleObj = handleObjIn ?
				jQuery.extend({}, handleObjIn) :
				{ handler: handler, data: data };

			// Namespaced event handlers
			if ( type.indexOf(".") > -1 ) {
				namespaces = type.split(".");
				type = namespaces.shift();
				handleObj.namespace = namespaces.slice(0).sort().join(".");

			} else {
				namespaces = [];
				handleObj.namespace = "";
			}

			handleObj.type = type;
			if ( !handleObj.guid ) {
				handleObj.guid = handler.guid;
			}

			// Get the current list of functions bound to this event
			var handlers = events[ type ],
				special = jQuery.event.special[ type ] || {};

			// Init the event handler queue
			if ( !handlers ) {
				handlers = events[ type ] = [];

				// Check for a special event handler
				// Only use addEventListener/attachEvent if the special
				// events handler returns false
				if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
					// Bind the global event handler to the element
					if ( elem.addEventListener ) {
						elem.addEventListener( type, eventHandle, false );

					} else if ( elem.attachEvent ) {
						elem.attachEvent( "on" + type, eventHandle );
					}
				}
			}

			if ( special.add ) {
				special.add.call( elem, handleObj );

				if ( !handleObj.handler.guid ) {
					handleObj.handler.guid = handler.guid;
				}
			}

			// Add the function to the element's handler list
			handlers.push( handleObj );

			// Keep track of which events have been used, for event optimization
			jQuery.event.global[ type ] = true;
		}

		// Nullify elem to prevent memory leaks in IE
		elem = null;
	},

	global: {},

	// Detach an event or set of events from an element
	remove: function( elem, types, handler, pos ) {
		// don't do events on text and comment nodes
		if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
			return;
		}

		if ( handler === false ) {
			handler = returnFalse;
		}

		var ret, type, fn, j, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType,
			elemData = jQuery.hasData( elem ) && jQuery._data( elem ),
			events = elemData && elemData.events;

		if ( !elemData || !events ) {
			return;
		}

		// types is actually an event object here
		if ( types && types.type ) {
			handler = types.handler;
			types = types.type;
		}

		// Unbind all events for the element
		if ( !types || typeof types === "string" && types.charAt(0) === "." ) {
			types = types || "";

			for ( type in events ) {
				jQuery.event.remove( elem, type + types );
			}

			return;
		}

		// Handle multiple events separated by a space
		// jQuery(...).unbind("mouseover mouseout", fn);
		types = types.split(" ");

		while ( (type = types[ i++ ]) ) {
			origType = type;
			handleObj = null;
			all = type.indexOf(".") < 0;
			namespaces = [];

			if ( !all ) {
				// Namespaced event handlers
				namespaces = type.split(".");
				type = namespaces.shift();

				namespace = new RegExp("(^|\\.)" +
					jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)");
			}

			eventType = events[ type ];

			if ( !eventType ) {
				continue;
			}

			if ( !handler ) {
				for ( j = 0; j < eventType.length; j++ ) {
					handleObj = eventType[ j ];

					if ( all || namespace.test( handleObj.namespace ) ) {
						jQuery.event.remove( elem, origType, handleObj.handler, j );
						eventType.splice( j--, 1 );
					}
				}

				continue;
			}

			special = jQuery.event.special[ type ] || {};

			for ( j = pos || 0; j < eventType.length; j++ ) {
				handleObj = eventType[ j ];

				if ( handler.guid === handleObj.guid ) {
					// remove the given handler for the given type
					if ( all || namespace.test( handleObj.namespace ) ) {
						if ( pos == null ) {
							eventType.splice( j--, 1 );
						}

						if ( special.remove ) {
							special.remove.call( elem, handleObj );
						}
					}

					if ( pos != null ) {
						break;
					}
				}
			}

			// remove generic event handler if no more handlers exist
			if ( eventType.length === 0 || pos != null && eventType.length === 1 ) {
				if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
					jQuery.removeEvent( elem, type, elemData.handle );
				}

				ret = null;
				delete events[ type ];
			}
		}

		// Remove the expando if it's no longer used
		if ( jQuery.isEmptyObject( events ) ) {
			var handle = elemData.handle;
			if ( handle ) {
				handle.elem = null;
			}

			delete elemData.events;
			delete elemData.handle;

			if ( jQuery.isEmptyObject( elemData ) ) {
				jQuery.removeData( elem, undefined, true );
			}
		}
	},
	
	// Events that are safe to short-circuit if no handlers are attached.
	// Native DOM events should not be added, they may have inline handlers.
	customEvent: {
		"getData": true,
		"setData": true,
		"changeData": true
	},

	trigger: function( event, data, elem, onlyHandlers ) {
		// Event object or event type
		var type = event.type || event,
			namespaces = [],
			exclusive;

		if ( type.indexOf("!") >= 0 ) {
			// Exclusive events trigger only for the exact event (no namespaces)
			type = type.slice(0, -1);
			exclusive = true;
		}

		if ( type.indexOf(".") >= 0 ) {
			// Namespaced trigger; create a regexp to match event type in handle()
			namespaces = type.split(".");
			type = namespaces.shift();
			namespaces.sort();
		}

		if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) {
			// No jQuery handlers for this event type, and it can't have inline handlers
			return;
		}

		// Caller can pass in an Event, Object, or just an event type string
		event = typeof event === "object" ?
			// jQuery.Event object
			event[ jQuery.expando ] ? event :
			// Object literal
			new jQuery.Event( type, event ) :
			// Just the event type (string)
			new jQuery.Event( type );

		event.type = type;
		event.exclusive = exclusive;
		event.namespace = namespaces.join(".");
		event.namespace_re = new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)");
		
		// triggerHandler() and global events don't bubble or run the default action
		if ( onlyHandlers || !elem ) {
			event.preventDefault();
			event.stopPropagation();
		}

		// Handle a global trigger
		if ( !elem ) {
			// TODO: Stop taunting the data cache; remove global events and always attach to document
			jQuery.each( jQuery.cache, function() {
				// internalKey variable is just used to make it easier to find
				// and potentially change this stuff later; currently it just
				// points to jQuery.expando
				var internalKey = jQuery.expando,
					internalCache = this[ internalKey ];
				if ( internalCache && internalCache.events && internalCache.events[ type ] ) {
					jQuery.event.trigger( event, data, internalCache.handle.elem );
				}
			});
			return;
		}

		// Don't do events on text and comment nodes
		if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
			return;
		}

		// Clean up the event in case it is being reused
		event.result = undefined;
		event.target = elem;

		// Clone any incoming data and prepend the event, creating the handler arg list
		data = data != null ? jQuery.makeArray( data ) : [];
		data.unshift( event );

		var cur = elem,
			// IE doesn't like method names with a colon (#3533, #8272)
			ontype = type.indexOf(":") < 0 ? "on" + type : "";

		// Fire event on the current element, then bubble up the DOM tree
		do {
			var handle = jQuery._data( cur, "handle" );

			event.currentTarget = cur;
			if ( handle ) {
				handle.apply( cur, data );
			}

			// Trigger an inline bound script
			if ( ontype && jQuery.acceptData( cur ) && cur[ ontype ] && cur[ ontype ].apply( cur, data ) === false ) {
				event.result = false;
				event.preventDefault();
			}

			// Bubble up to document, then to window
			cur = cur.parentNode || cur.ownerDocument || cur === event.target.ownerDocument && window;
		} while ( cur && !event.isPropagationStopped() );

		// If nobody prevented the default action, do it now
		if ( !event.isDefaultPrevented() ) {
			var old,
				special = jQuery.event.special[ type ] || {};

			if ( (!special._default || special._default.call( elem.ownerDocument, event ) === false) &&
				!(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) {

				// Call a native DOM method on the target with the same name name as the event.
				// Can't use an .isFunction)() check here because IE6/7 fails that test.
				// IE<9 dies on focus to hidden element (#1486), may want to revisit a try/catch.
				try {
					if ( ontype && elem[ type ] ) {
						// Don't re-trigger an onFOO event when we call its FOO() method
						old = elem[ ontype ];

						if ( old ) {
							elem[ ontype ] = null;
						}

						jQuery.event.triggered = type;
						elem[ type ]();
					}
				} catch ( ieError ) {}

				if ( old ) {
					elem[ ontype ] = old;
				}

				jQuery.event.triggered = undefined;
			}
		}
		
		return event.result;
	},

	handle: function( event ) {
		event = jQuery.event.fix( event || window.event );
		// Snapshot the handlers list since a called handler may add/remove events.
		var handlers = ((jQuery._data( this, "events" ) || {})[ event.type ] || []).slice(0),
			run_all = !event.exclusive && !event.namespace,
			args = Array.prototype.slice.call( arguments, 0 );

		// Use the fix-ed Event rather than the (read-only) native event
		args[0] = event;
		event.currentTarget = this;

		for ( var j = 0, l = handlers.length; j < l; j++ ) {
			var handleObj = handlers[ j ];

			// Triggered event must 1) be non-exclusive and have no namespace, or
			// 2) have namespace(s) a subset or equal to those in the bound event.
			if ( run_all || event.namespace_re.test( handleObj.namespace ) ) {
				// Pass in a reference to the handler function itself
				// So that we can later remove it
				event.handler = handleObj.handler;
				event.data = handleObj.data;
				event.handleObj = handleObj;

				var ret = handleObj.handler.apply( this, args );

				if ( ret !== undefined ) {
					event.result = ret;
					if ( ret === false ) {
						event.preventDefault();
						event.stopPropagation();
					}
				}

				if ( event.isImmediatePropagationStopped() ) {
					break;
				}
			}
		}
		return event.result;
	},

	props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),

	fix: function( event ) {
		if ( event[ jQuery.expando ] ) {
			return event;
		}

		// store a copy of the original event object
		// and "clone" to set read-only properties
		var originalEvent = event;
		event = jQuery.Event( originalEvent );

		for ( var i = this.props.length, prop; i; ) {
			prop = this.props[ --i ];
			event[ prop ] = originalEvent[ prop ];
		}

		// Fix target property, if necessary
		if ( !event.target ) {
			// Fixes #1925 where srcElement might not be defined either
			event.target = event.srcElement || document;
		}

		// check if target is a textnode (safari)
		if ( event.target.nodeType === 3 ) {
			event.target = event.target.parentNode;
		}

		// Add relatedTarget, if necessary
		if ( !event.relatedTarget && event.fromElement ) {
			event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;
		}

		// Calculate pageX/Y if missing and clientX/Y available
		if ( event.pageX == null && event.clientX != null ) {
			var eventDocument = event.target.ownerDocument || document,
				doc = eventDocument.documentElement,
				body = eventDocument.body;

			event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
			event.pageY = event.clientY + (doc && doc.scrollTop  || body && body.scrollTop  || 0) - (doc && doc.clientTop  || body && body.clientTop  || 0);
		}

		// Add which for key events
		if ( event.which == null && (event.charCode != null || event.keyCode != null) ) {
			event.which = event.charCode != null ? event.charCode : event.keyCode;
		}

		// Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
		if ( !event.metaKey && event.ctrlKey ) {
			event.metaKey = event.ctrlKey;
		}

		// Add which for click: 1 === left; 2 === middle; 3 === right
		// Note: button is not normalized, so don't use it
		if ( !event.which && event.button !== undefined ) {
			event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
		}

		return event;
	},

	// Deprecated, use jQuery.guid instead
	guid: 1E8,

	// Deprecated, use jQuery.proxy instead
	proxy: jQuery.proxy,

	special: {
		ready: {
			// Make sure the ready event is setup
			setup: jQuery.bindReady,
			teardown: jQuery.noop
		},

		live: {
			add: function( handleObj ) {
				jQuery.event.add( this,
					liveConvert( handleObj.origType, handleObj.selector ),
					jQuery.extend({}, handleObj, {handler: liveHandler, guid: handleObj.handler.guid}) );
			},

			remove: function( handleObj ) {
				jQuery.event.remove( this, liveConvert( handleObj.origType, handleObj.selector ), handleObj );
			}
		},

		beforeunload: {
			setup: function( data, namespaces, eventHandle ) {
				// We only want to do this special case on windows
				if ( jQuery.isWindow( this ) ) {
					this.onbeforeunload = eventHandle;
				}
			},

			teardown: function( namespaces, eventHandle ) {
				if ( this.onbeforeunload === eventHandle ) {
					this.onbeforeunload = null;
				}
			}
		}
	}
};

jQuery.removeEvent = document.removeEventListener ?
	function( elem, type, handle ) {
		if ( elem.removeEventListener ) {
			elem.removeEventListener( type, handle, false );
		}
	} :
	function( elem, type, handle ) {
		if ( elem.detachEvent ) {
			elem.detachEvent( "on" + type, handle );
		}
	};

jQuery.Event = function( src, props ) {
	// Allow instantiation without the 'new' keyword
	if ( !this.preventDefault ) {
		return new jQuery.Event( src, props );
	}

	// Event object
	if ( src && src.type ) {
		this.originalEvent = src;
		this.type = src.type;

		// Events bubbling up the document may have been marked as prevented
		// by a handler lower down the tree; reflect the correct value.
		this.isDefaultPrevented = (src.defaultPrevented || src.returnValue === false ||
			src.getPreventDefault && src.getPreventDefault()) ? returnTrue : returnFalse;

	// Event type
	} else {
		this.type = src;
	}

	// Put explicitly provided properties onto the event object
	if ( props ) {
		jQuery.extend( this, props );
	}

	// timeStamp is buggy for some events on Firefox(#3843)
	// So we won't rely on the native value
	this.timeStamp = jQuery.now();

	// Mark it as fixed
	this[ jQuery.expando ] = true;
};

function returnFalse() {
	return false;
}
function returnTrue() {
	return true;
}

// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
jQuery.Event.prototype = {
	preventDefault: function() {
		this.isDefaultPrevented = returnTrue;

		var e = this.originalEvent;
		if ( !e ) {
			return;
		}

		// if preventDefault exists run it on the original event
		if ( e.preventDefault ) {
			e.preventDefault();

		// otherwise set the returnValue property of the original event to false (IE)
		} else {
			e.returnValue = false;
		}
	},
	stopPropagation: function() {
		this.isPropagationStopped = returnTrue;

		var e = this.originalEvent;
		if ( !e ) {
			return;
		}
		// if stopPropagation exists run it on the original event
		if ( e.stopPropagation ) {
			e.stopPropagation();
		}
		// otherwise set the cancelBubble property of the original event to true (IE)
		e.cancelBubble = true;
	},
	stopImmediatePropagation: function() {
		this.isImmediatePropagationStopped = returnTrue;
		this.stopPropagation();
	},
	isDefaultPrevented: returnFalse,
	isPropagationStopped: returnFalse,
	isImmediatePropagationStopped: returnFalse
};

// Checks if an event happened on an element within another element
// Used in jQuery.event.special.mouseenter and mouseleave handlers
var withinElement = function( event ) {

	// Check if mouse(over|out) are still within the same parent element
	var related = event.relatedTarget,
		inside = false,
		eventType = event.type;

	event.type = event.data;

	if ( related !== this ) {

		if ( related ) {
			inside = jQuery.contains( this, related );
		}

		if ( !inside ) {

			jQuery.event.handle.apply( this, arguments );

			event.type = eventType;
		}
	}
},

// In case of event delegation, we only need to rename the event.type,
// liveHandler will take care of the rest.
delegate = function( event ) {
	event.type = event.data;
	jQuery.event.handle.apply( this, arguments );
};

// Create mouseenter and mouseleave events
jQuery.each({
	mouseenter: "mouseover",
	mouseleave: "mouseout"
}, function( orig, fix ) {
	jQuery.event.special[ orig ] = {
		setup: function( data ) {
			jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig );
		},
		teardown: function( data ) {
			jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement );
		}
	};
});

// submit delegation
if ( !jQuery.support.submitBubbles ) {

	jQuery.event.special.submit = {
		setup: function( data, namespaces ) {
			if ( !jQuery.nodeName( this, "form" ) ) {
				jQuery.event.add(this, "click.specialSubmit", function( e ) {
					var elem = e.target,
						type = elem.type;

					if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) {
						trigger( "submit", this, arguments );
					}
				});

				jQuery.event.add(this, "keypress.specialSubmit", function( e ) {
					var elem = e.target,
						type = elem.type;

					if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) {
						trigger( "submit", this, arguments );
					}
				});

			} else {
				return false;
			}
		},

		teardown: function( namespaces ) {
			jQuery.event.remove( this, ".specialSubmit" );
		}
	};

}

// change delegation, happens here so we have bind.
if ( !jQuery.support.changeBubbles ) {

	var changeFilters,

	getVal = function( elem ) {
		var type = elem.type, val = elem.value;

		if ( type === "radio" || type === "checkbox" ) {
			val = elem.checked;

		} else if ( type === "select-multiple" ) {
			val = elem.selectedIndex > -1 ?
				jQuery.map( elem.options, function( elem ) {
					return elem.selected;
				}).join("-") :
				"";

		} else if ( jQuery.nodeName( elem, "select" ) ) {
			val = elem.selectedIndex;
		}

		return val;
	},

	testChange = function testChange( e ) {
		var elem = e.target, data, val;

		if ( !rformElems.test( elem.nodeName ) || elem.readOnly ) {
			return;
		}

		data = jQuery._data( elem, "_change_data" );
		val = getVal(elem);

		// the current data will be also retrieved by beforeactivate
		if ( e.type !== "focusout" || elem.type !== "radio" ) {
			jQuery._data( elem, "_change_data", val );
		}

		if ( data === undefined || val === data ) {
			return;
		}

		if ( data != null || val ) {
			e.type = "change";
			e.liveFired = undefined;
			jQuery.event.trigger( e, arguments[1], elem );
		}
	};

	jQuery.event.special.change = {
		filters: {
			focusout: testChange,

			beforedeactivate: testChange,

			click: function( e ) {
				var elem = e.target, type = jQuery.nodeName( elem, "input" ) ? elem.type : "";

				if ( type === "radio" || type === "checkbox" || jQuery.nodeName( elem, "select" ) ) {
					testChange.call( this, e );
				}
			},

			// Change has to be called before submit
			// Keydown will be called before keypress, which is used in submit-event delegation
			keydown: function( e ) {
				var elem = e.target, type = jQuery.nodeName( elem, "input" ) ? elem.type : "";

				if ( (e.keyCode === 13 && !jQuery.nodeName( elem, "textarea" ) ) ||
					(e.keyCode === 32 && (type === "checkbox" || type === "radio")) ||
					type === "select-multiple" ) {
					testChange.call( this, e );
				}
			},

			// Beforeactivate happens also before the previous element is blurred
			// with this event you can't trigger a change event, but you can store
			// information
			beforeactivate: function( e ) {
				var elem = e.target;
				jQuery._data( elem, "_change_data", getVal(elem) );
			}
		},

		setup: function( data, namespaces ) {
			if ( this.type === "file" ) {
				return false;
			}

			for ( var type in changeFilters ) {
				jQuery.event.add( this, type + ".specialChange", changeFilters[type] );
			}

			return rformElems.test( this.nodeName );
		},

		teardown: function( namespaces ) {
			jQuery.event.remove( this, ".specialChange" );

			return rformElems.test( this.nodeName );
		}
	};

	changeFilters = jQuery.event.special.change.filters;

	// Handle when the input is .focus()'d
	changeFilters.focus = changeFilters.beforeactivate;
}

function trigger( type, elem, args ) {
	// Piggyback on a donor event to simulate a different one.
	// Fake originalEvent to avoid donor's stopPropagation, but if the
	// simulated event prevents default then we do the same on the donor.
	// Don't pass args or remember liveFired; they apply to the donor event.
	var event = jQuery.extend( {}, args[ 0 ] );
	event.type = type;
	event.originalEvent = {};
	event.liveFired = undefined;
	jQuery.event.handle.call( elem, event );
	if ( event.isDefaultPrevented() ) {
		args[ 0 ].preventDefault();
	}
}

// Create "bubbling" focus and blur events
if ( !jQuery.support.focusinBubbles ) {
	jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {

		// Attach a single capturing handler while someone wants focusin/focusout
		var attaches = 0;

		jQuery.event.special[ fix ] = {
			setup: function() {
				if ( attaches++ === 0 ) {
					document.addEventListener( orig, handler, true );
				}
			},
			teardown: function() {
				if ( --attaches === 0 ) {
					document.removeEventListener( orig, handler, true );
				}
			}
		};

		function handler( donor ) {
			// Donor event is always a native one; fix it and switch its type.
			// Let focusin/out handler cancel the donor focus/blur event.
			var e = jQuery.event.fix( donor );
			e.type = fix;
			e.originalEvent = {};
			jQuery.event.trigger( e, null, e.target );
			if ( e.isDefaultPrevented() ) {
				donor.preventDefault();
			}
		}
	});
}

jQuery.each(["bind", "one"], function( i, name ) {
	jQuery.fn[ name ] = function( type, data, fn ) {
		var handler;

		// Handle object literals
		if ( typeof type === "object" ) {
			for ( var key in type ) {
				this[ name ](key, data, type[key], fn);
			}
			return this;
		}

		if ( arguments.length === 2 || data === false ) {
			fn = data;
			data = undefined;
		}

		if ( name === "one" ) {
			handler = function( event ) {
				jQuery( this ).unbind( event, handler );
				return fn.apply( this, arguments );
			};
			handler.guid = fn.guid || jQuery.guid++;
		} else {
			handler = fn;
		}

		if ( type === "unload" && name !== "one" ) {
			this.one( type, data, fn );

		} else {
			for ( var i = 0, l = this.length; i < l; i++ ) {
				jQuery.event.add( this[i], type, handler, data );
			}
		}

		return this;
	};
});

jQuery.fn.extend({
	unbind: function( type, fn ) {
		// Handle object literals
		if ( typeof type === "object" && !type.preventDefault ) {
			for ( var key in type ) {
				this.unbind(key, type[key]);
			}

		} else {
			for ( var i = 0, l = this.length; i < l; i++ ) {
				jQuery.event.remove( this[i], type, fn );
			}
		}

		return this;
	},

	delegate: function( selector, types, data, fn ) {
		return this.live( types, data, fn, selector );
	},

	undelegate: function( selector, types, fn ) {
		if ( arguments.length === 0 ) {
			return this.unbind( "live" );

		} else {
			return this.die( types, null, fn, selector );
		}
	},

	trigger: function( type, data ) {
		return this.each(function() {
			jQuery.event.trigger( type, data, this );
		});
	},

	triggerHandler: function( type, data ) {
		if ( this[0] ) {
			return jQuery.event.trigger( type, data, this[0], true );
		}
	},

	toggle: function( fn ) {
		// Save reference to arguments for access in closure
		var args = arguments,
			guid = fn.guid || jQuery.guid++,
			i = 0,
			toggler = function( event ) {
				// Figure out which function to execute
				var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i;
				jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 );

				// Make sure that clicks stop
				event.preventDefault();

				// and execute the function
				return args[ lastToggle ].apply( this, arguments ) || false;
			};

		// link all the functions, so any of them can unbind this click handler
		toggler.guid = guid;
		while ( i < args.length ) {
			args[ i++ ].guid = guid;
		}

		return this.click( toggler );
	},

	hover: function( fnOver, fnOut ) {
		return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
	}
});

var liveMap = {
	focus: "focusin",
	blur: "focusout",
	mouseenter: "mouseover",
	mouseleave: "mouseout"
};

jQuery.each(["live", "die"], function( i, name ) {
	jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) {
		var type, i = 0, match, namespaces, preType,
			selector = origSelector || this.selector,
			context = origSelector ? this : jQuery( this.context );

		if ( typeof types === "object" && !types.preventDefault ) {
			for ( var key in types ) {
				context[ name ]( key, data, types[key], selector );
			}

			return this;
		}

		if ( name === "die" && !types &&
					origSelector && origSelector.charAt(0) === "." ) {

			context.unbind( origSelector );

			return this;
		}

		if ( data === false || jQuery.isFunction( data ) ) {
			fn = data || returnFalse;
			data = undefined;
		}

		types = (types || "").split(" ");

		while ( (type = types[ i++ ]) != null ) {
			match = rnamespaces.exec( type );
			namespaces = "";

			if ( match )  {
				namespaces = match[0];
				type = type.replace( rnamespaces, "" );
			}

			if ( type === "hover" ) {
				types.push( "mouseenter" + namespaces, "mouseleave" + namespaces );
				continue;
			}

			preType = type;

			if ( liveMap[ type ] ) {
				types.push( liveMap[ type ] + namespaces );
				type = type + namespaces;

			} else {
				type = (liveMap[ type ] || type) + namespaces;
			}

			if ( name === "live" ) {
				// bind live handler
				for ( var j = 0, l = context.length; j < l; j++ ) {
					jQuery.event.add( context[j], "live." + liveConvert( type, selector ),
						{ data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } );
				}

			} else {
				// unbind live handler
				context.unbind( "live." + liveConvert( type, selector ), fn );
			}
		}

		return this;
	};
});

function liveHandler( event ) {
	var stop, maxLevel, related, match, handleObj, elem, j, i, l, data, close, namespace, ret,
		elems = [],
		selectors = [],
		events = jQuery._data( this, "events" );

	// Make sure we avoid non-left-click bubbling in Firefox (#3861) and disabled elements in IE (#6911)
	if ( event.liveFired === this || !events || !events.live || event.target.disabled || event.button && event.type === "click" ) {
		return;
	}

	if ( event.namespace ) {
		namespace = new RegExp("(^|\\.)" + event.namespace.split(".").join("\\.(?:.*\\.)?") + "(\\.|$)");
	}

	event.liveFired = this;

	var live = events.live.slice(0);

	for ( j = 0; j < live.length; j++ ) {
		handleObj = live[j];

		if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) {
			selectors.push( handleObj.selector );

		} else {
			live.splice( j--, 1 );
		}
	}

	match = jQuery( event.target ).closest( selectors, event.currentTarget );

	for ( i = 0, l = match.length; i < l; i++ ) {
		close = match[i];

		for ( j = 0; j < live.length; j++ ) {
			handleObj = live[j];

			if ( close.selector === handleObj.selector && (!namespace || namespace.test( handleObj.namespace )) && !close.elem.disabled ) {
				elem = close.elem;
				related = null;

				// Those two events require additional checking
				if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) {
					event.type = handleObj.preType;
					related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0];

					// Make sure not to accidentally match a child element with the same selector
					if ( related && jQuery.contains( elem, related ) ) {
						related = elem;
					}
				}

				if ( !related || related !== elem ) {
					elems.push({ elem: elem, handleObj: handleObj, level: close.level });
				}
			}
		}
	}

	for ( i = 0, l = elems.length; i < l; i++ ) {
		match = elems[i];

		if ( maxLevel && match.level > maxLevel ) {
			break;
		}

		event.currentTarget = match.elem;
		event.data = match.handleObj.data;
		event.handleObj = match.handleObj;

		ret = match.handleObj.origHandler.apply( match.elem, arguments );

		if ( ret === false || event.isPropagationStopped() ) {
			maxLevel = match.level;

			if ( ret === false ) {
				stop = false;
			}
			if ( event.isImmediatePropagationStopped() ) {
				break;
			}
		}
	}

	return stop;
}

function liveConvert( type, selector ) {
	return (type && type !== "*" ? type + "." : "") + selector.replace(rperiod, "`").replace(rspaces, "&");
}

jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
	"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
	"change select submit keydown keypress keyup error").split(" "), function( i, name ) {

	// Handle event binding
	jQuery.fn[ name ] = function( data, fn ) {
		if ( fn == null ) {
			fn = data;
			data = null;
		}

		return arguments.length > 0 ?
			this.bind( name, data, fn ) :
			this.trigger( name );
	};

	if ( jQuery.attrFn ) {
		jQuery.attrFn[ name ] = true;
	}
});



/*!
 * Sizzle CSS Selector Engine
 *  Copyright 2011, The Dojo Foundation
 *  Released under the MIT, BSD, and GPL Licenses.
 *  More information: http://sizzlejs.com/
 */
(function(){

var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
	done = 0,
	toString = Object.prototype.toString,
	hasDuplicate = false,
	baseHasDuplicate = true,
	rBackslash = /\\/g,
	rNonWord = /\W/;

// Here we check if the JavaScript engine is using some sort of
// optimization where it does not always call our comparision
// function. If that is the case, discard the hasDuplicate value.
//   Thus far that includes Google Chrome.
[0, 0].sort(function() {
	baseHasDuplicate = false;
	return 0;
});

var Sizzle = function( selector, context, results, seed ) {
	results = results || [];
	context = context || document;

	var origContext = context;

	if ( context.nodeType !== 1 && context.nodeType !== 9 ) {
		return [];
	}
	
	if ( !selector || typeof selector !== "string" ) {
		return results;
	}

	var m, set, checkSet, extra, ret, cur, pop, i,
		prune = true,
		contextXML = Sizzle.isXML( context ),
		parts = [],
		soFar = selector;
	
	// Reset the position of the chunker regexp (start from head)
	do {
		chunker.exec( "" );
		m = chunker.exec( soFar );

		if ( m ) {
			soFar = m[3];
		
			parts.push( m[1] );
		
			if ( m[2] ) {
				extra = m[3];
				break;
			}
		}
	} while ( m );

	if ( parts.length > 1 && origPOS.exec( selector ) ) {

		if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
			set = posProcess( parts[0] + parts[1], context );

		} else {
			set = Expr.relative[ parts[0] ] ?
				[ context ] :
				Sizzle( parts.shift(), context );

			while ( parts.length ) {
				selector = parts.shift();

				if ( Expr.relative[ selector ] ) {
					selector += parts.shift();
				}
				
				set = posProcess( selector, set );
			}
		}

	} else {
		// Take a shortcut and set the context if the root selector is an ID
		// (but not if it'll be faster if the inner selector is an ID)
		if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&
				Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {

			ret = Sizzle.find( parts.shift(), context, contextXML );
			context = ret.expr ?
				Sizzle.filter( ret.expr, ret.set )[0] :
				ret.set[0];
		}

		if ( context ) {
			ret = seed ?
				{ expr: parts.pop(), set: makeArray(seed) } :
				Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML );

			set = ret.expr ?
				Sizzle.filter( ret.expr, ret.set ) :
				ret.set;

			if ( parts.length > 0 ) {
				checkSet = makeArray( set );

			} else {
				prune = false;
			}

			while ( parts.length ) {
				cur = parts.pop();
				pop = cur;

				if ( !Expr.relative[ cur ] ) {
					cur = "";
				} else {
					pop = parts.pop();
				}

				if ( pop == null ) {
					pop = context;
				}

				Expr.relative[ cur ]( checkSet, pop, contextXML );
			}

		} else {
			checkSet = parts = [];
		}
	}

	if ( !checkSet ) {
		checkSet = set;
	}

	if ( !checkSet ) {
		Sizzle.error( cur || selector );
	}

	if ( toString.call(checkSet) === "[object Array]" ) {
		if ( !prune ) {
			results.push.apply( results, checkSet );

		} else if ( context && context.nodeType === 1 ) {
			for ( i = 0; checkSet[i] != null; i++ ) {
				if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) {
					results.push( set[i] );
				}
			}

		} else {
			for ( i = 0; checkSet[i] != null; i++ ) {
				if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
					results.push( set[i] );
				}
			}
		}

	} else {
		makeArray( checkSet, results );
	}

	if ( extra ) {
		Sizzle( extra, origContext, results, seed );
		Sizzle.uniqueSort( results );
	}

	return results;
};

Sizzle.uniqueSort = function( results ) {
	if ( sortOrder ) {
		hasDuplicate = baseHasDuplicate;
		results.sort( sortOrder );

		if ( hasDuplicate ) {
			for ( var i = 1; i < results.length; i++ ) {
				if ( results[i] === results[ i - 1 ] ) {
					results.splice( i--, 1 );
				}
			}
		}
	}

	return results;
};

Sizzle.matches = function( expr, set ) {
	return Sizzle( expr, null, null, set );
};

Sizzle.matchesSelector = function( node, expr ) {
	return Sizzle( expr, null, null, [node] ).length > 0;
};

Sizzle.find = function( expr, context, isXML ) {
	var set;

	if ( !expr ) {
		return [];
	}

	for ( var i = 0, l = Expr.order.length; i < l; i++ ) {
		var match,
			type = Expr.order[i];
		
		if ( (match = Expr.leftMatch[ type ].exec( expr )) ) {
			var left = match[1];
			match.splice( 1, 1 );

			if ( left.substr( left.length - 1 ) !== "\\" ) {
				match[1] = (match[1] || "").replace( rBackslash, "" );
				set = Expr.find[ type ]( match, context, isXML );

				if ( set != null ) {
					expr = expr.replace( Expr.match[ type ], "" );
					break;
				}
			}
		}
	}

	if ( !set ) {
		set = typeof context.getElementsByTagName !== "undefined" ?
			context.getElementsByTagName( "*" ) :
			[];
	}

	return { set: set, expr: expr };
};

Sizzle.filter = function( expr, set, inplace, not ) {
	var match, anyFound,
		old = expr,
		result = [],
		curLoop = set,
		isXMLFilter = set && set[0] && Sizzle.isXML( set[0] );

	while ( expr && set.length ) {
		for ( var type in Expr.filter ) {
			if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) {
				var found, item,
					filter = Expr.filter[ type ],
					left = match[1];

				anyFound = false;

				match.splice(1,1);

				if ( left.substr( left.length - 1 ) === "\\" ) {
					continue;
				}

				if ( curLoop === result ) {
					result = [];
				}

				if ( Expr.preFilter[ type ] ) {
					match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );

					if ( !match ) {
						anyFound = found = true;

					} else if ( match === true ) {
						continue;
					}
				}

				if ( match ) {
					for ( var i = 0; (item = curLoop[i]) != null; i++ ) {
						if ( item ) {
							found = filter( item, match, i, curLoop );
							var pass = not ^ !!found;

							if ( inplace && found != null ) {
								if ( pass ) {
									anyFound = true;

								} else {
									curLoop[i] = false;
								}

							} else if ( pass ) {
								result.push( item );
								anyFound = true;
							}
						}
					}
				}

				if ( found !== undefined ) {
					if ( !inplace ) {
						curLoop = result;
					}

					expr = expr.replace( Expr.match[ type ], "" );

					if ( !anyFound ) {
						return [];
					}

					break;
				}
			}
		}

		// Improper expression
		if ( expr === old ) {
			if ( anyFound == null ) {
				Sizzle.error( expr );

			} else {
				break;
			}
		}

		old = expr;
	}

	return curLoop;
};

Sizzle.error = function( msg ) {
	throw "Syntax error, unrecognized expression: " + msg;
};

var Expr = Sizzle.selectors = {
	order: [ "ID", "NAME", "TAG" ],

	match: {
		ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
		CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
		NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,
		ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,
		TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,
		CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,
		POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,
		PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/
	},

	leftMatch: {},

	attrMap: {
		"class": "className",
		"for": "htmlFor"
	},

	attrHandle: {
		href: function( elem ) {
			return elem.getAttribute( "href" );
		},
		type: function( elem ) {
			return elem.getAttribute( "type" );
		}
	},

	relative: {
		"+": function(checkSet, part){
			var isPartStr = typeof part === "string",
				isTag = isPartStr && !rNonWord.test( part ),
				isPartStrNotTag = isPartStr && !isTag;

			if ( isTag ) {
				part = part.toLowerCase();
			}

			for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
				if ( (elem = checkSet[i]) ) {
					while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}

					checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ?
						elem || false :
						elem === part;
				}
			}

			if ( isPartStrNotTag ) {
				Sizzle.filter( part, checkSet, true );
			}
		},

		">": function( checkSet, part ) {
			var elem,
				isPartStr = typeof part === "string",
				i = 0,
				l = checkSet.length;

			if ( isPartStr && !rNonWord.test( part ) ) {
				part = part.toLowerCase();

				for ( ; i < l; i++ ) {
					elem = checkSet[i];

					if ( elem ) {
						var parent = elem.parentNode;
						checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false;
					}
				}

			} else {
				for ( ; i < l; i++ ) {
					elem = checkSet[i];

					if ( elem ) {
						checkSet[i] = isPartStr ?
							elem.parentNode :
							elem.parentNode === part;
					}
				}

				if ( isPartStr ) {
					Sizzle.filter( part, checkSet, true );
				}
			}
		},

		"": function(checkSet, part, isXML){
			var nodeCheck,
				doneName = done++,
				checkFn = dirCheck;

			if ( typeof part === "string" && !rNonWord.test( part ) ) {
				part = part.toLowerCase();
				nodeCheck = part;
				checkFn = dirNodeCheck;
			}

			checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML );
		},

		"~": function( checkSet, part, isXML ) {
			var nodeCheck,
				doneName = done++,
				checkFn = dirCheck;

			if ( typeof part === "string" && !rNonWord.test( part ) ) {
				part = part.toLowerCase();
				nodeCheck = part;
				checkFn = dirNodeCheck;
			}

			checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML );
		}
	},

	find: {
		ID: function( match, context, isXML ) {
			if ( typeof context.getElementById !== "undefined" && !isXML ) {
				var m = context.getElementById(match[1]);
				// Check parentNode to catch when Blackberry 4.6 returns
				// nodes that are no longer in the document #6963
				return m && m.parentNode ? [m] : [];
			}
		},

		NAME: function( match, context ) {
			if ( typeof context.getElementsByName !== "undefined" ) {
				var ret = [],
					results = context.getElementsByName( match[1] );

				for ( var i = 0, l = results.length; i < l; i++ ) {
					if ( results[i].getAttribute("name") === match[1] ) {
						ret.push( results[i] );
					}
				}

				return ret.length === 0 ? null : ret;
			}
		},

		TAG: function( match, context ) {
			if ( typeof context.getElementsByTagName !== "undefined" ) {
				return context.getElementsByTagName( match[1] );
			}
		}
	},
	preFilter: {
		CLASS: function( match, curLoop, inplace, result, not, isXML ) {
			match = " " + match[1].replace( rBackslash, "" ) + " ";

			if ( isXML ) {
				return match;
			}

			for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
				if ( elem ) {
					if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n\r]/g, " ").indexOf(match) >= 0) ) {
						if ( !inplace ) {
							result.push( elem );
						}

					} else if ( inplace ) {
						curLoop[i] = false;
					}
				}
			}

			return false;
		},

		ID: function( match ) {
			return match[1].replace( rBackslash, "" );
		},

		TAG: function( match, curLoop ) {
			return match[1].replace( rBackslash, "" ).toLowerCase();
		},

		CHILD: function( match ) {
			if ( match[1] === "nth" ) {
				if ( !match[2] ) {
					Sizzle.error( match[0] );
				}

				match[2] = match[2].replace(/^\+|\s*/g, '');

				// parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
				var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec(
					match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" ||
					!/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);

				// calculate the numbers (first)n+(last) including if they are negative
				match[2] = (test[1] + (test[2] || 1)) - 0;
				match[3] = test[3] - 0;
			}
			else if ( match[2] ) {
				Sizzle.error( match[0] );
			}

			// TODO: Move to normal caching system
			match[0] = done++;

			return match;
		},

		ATTR: function( match, curLoop, inplace, result, not, isXML ) {
			var name = match[1] = match[1].replace( rBackslash, "" );
			
			if ( !isXML && Expr.attrMap[name] ) {
				match[1] = Expr.attrMap[name];
			}

			// Handle if an un-quoted value was used
			match[4] = ( match[4] || match[5] || "" ).replace( rBackslash, "" );

			if ( match[2] === "~=" ) {
				match[4] = " " + match[4] + " ";
			}

			return match;
		},

		PSEUDO: function( match, curLoop, inplace, result, not ) {
			if ( match[1] === "not" ) {
				// If we're dealing with a complex expression, or a simple one
				if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) {
					match[3] = Sizzle(match[3], null, null, curLoop);

				} else {
					var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);

					if ( !inplace ) {
						result.push.apply( result, ret );
					}

					return false;
				}

			} else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {
				return true;
			}
			
			return match;
		},

		POS: function( match ) {
			match.unshift( true );

			return match;
		}
	},
	
	filters: {
		enabled: function( elem ) {
			return elem.disabled === false && elem.type !== "hidden";
		},

		disabled: function( elem ) {
			return elem.disabled === true;
		},

		checked: function( elem ) {
			return elem.checked === true;
		},
		
		selected: function( elem ) {
			// Accessing this property makes selected-by-default
			// options in Safari work properly
			if ( elem.parentNode ) {
				elem.parentNode.selectedIndex;
			}
			
			return elem.selected === true;
		},

		parent: function( elem ) {
			return !!elem.firstChild;
		},

		empty: function( elem ) {
			return !elem.firstChild;
		},

		has: function( elem, i, match ) {
			return !!Sizzle( match[3], elem ).length;
		},

		header: function( elem ) {
			return (/h\d/i).test( elem.nodeName );
		},

		text: function( elem ) {
			var attr = elem.getAttribute( "type" ), type = elem.type;
			// IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) 
			// use getAttribute instead to test this case
			return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null );
		},

		radio: function( elem ) {
			return elem.nodeName.toLowerCase() === "input" && "radio" === elem.type;
		},

		checkbox: function( elem ) {
			return elem.nodeName.toLowerCase() === "input" && "checkbox" === elem.type;
		},

		file: function( elem ) {
			return elem.nodeName.toLowerCase() === "input" && "file" === elem.type;
		},

		password: function( elem ) {
			return elem.nodeName.toLowerCase() === "input" && "password" === elem.type;
		},

		submit: function( elem ) {
			var name = elem.nodeName.toLowerCase();
			return (name === "input" || name === "button") && "submit" === elem.type;
		},

		image: function( elem ) {
			return elem.nodeName.toLowerCase() === "input" && "image" === elem.type;
		},

		reset: function( elem ) {
			var name = elem.nodeName.toLowerCase();
			return (name === "input" || name === "button") && "reset" === elem.type;
		},

		button: function( elem ) {
			var name = elem.nodeName.toLowerCase();
			return name === "input" && "button" === elem.type || name === "button";
		},

		input: function( elem ) {
			return (/input|select|textarea|button/i).test( elem.nodeName );
		},

		focus: function( elem ) {
			return elem === elem.ownerDocument.activeElement;
		}
	},
	setFilters: {
		first: function( elem, i ) {
			return i === 0;
		},

		last: function( elem, i, match, array ) {
			return i === array.length - 1;
		},

		even: function( elem, i ) {
			return i % 2 === 0;
		},

		odd: function( elem, i ) {
			return i % 2 === 1;
		},

		lt: function( elem, i, match ) {
			return i < match[3] - 0;
		},

		gt: function( elem, i, match ) {
			return i > match[3] - 0;
		},

		nth: function( elem, i, match ) {
			return match[3] - 0 === i;
		},

		eq: function( elem, i, match ) {
			return match[3] - 0 === i;
		}
	},
	filter: {
		PSEUDO: function( elem, match, i, array ) {
			var name = match[1],
				filter = Expr.filters[ name ];

			if ( filter ) {
				return filter( elem, i, match, array );

			} else if ( name === "contains" ) {
				return (elem.textContent || elem.innerText || Sizzle.getText([ elem ]) || "").indexOf(match[3]) >= 0;

			} else if ( name === "not" ) {
				var not = match[3];

				for ( var j = 0, l = not.length; j < l; j++ ) {
					if ( not[j] === elem ) {
						return false;
					}
				}

				return true;

			} else {
				Sizzle.error( name );
			}
		},

		CHILD: function( elem, match ) {
			var type = match[1],
				node = elem;

			switch ( type ) {
				case "only":
				case "first":
					while ( (node = node.previousSibling) )	 {
						if ( node.nodeType === 1 ) { 
							return false; 
						}
					}

					if ( type === "first" ) { 
						return true; 
					}

					node = elem;

				case "last":
					while ( (node = node.nextSibling) )	 {
						if ( node.nodeType === 1 ) { 
							return false; 
						}
					}

					return true;

				case "nth":
					var first = match[2],
						last = match[3];

					if ( first === 1 && last === 0 ) {
						return true;
					}
					
					var doneName = match[0],
						parent = elem.parentNode;
	
					if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) {
						var count = 0;
						
						for ( node = parent.firstChild; node; node = node.nextSibling ) {
							if ( node.nodeType === 1 ) {
								node.nodeIndex = ++count;
							}
						} 

						parent.sizcache = doneName;
					}
					
					var diff = elem.nodeIndex - last;

					if ( first === 0 ) {
						return diff === 0;

					} else {
						return ( diff % first === 0 && diff / first >= 0 );
					}
			}
		},

		ID: function( elem, match ) {
			return elem.nodeType === 1 && elem.getAttribute("id") === match;
		},

		TAG: function( elem, match ) {
			return (match === "*" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match;
		},
		
		CLASS: function( elem, match ) {
			return (" " + (elem.className || elem.getAttribute("class")) + " ")
				.indexOf( match ) > -1;
		},

		ATTR: function( elem, match ) {
			var name = match[1],
				result = Expr.attrHandle[ name ] ?
					Expr.attrHandle[ name ]( elem ) :
					elem[ name ] != null ?
						elem[ name ] :
						elem.getAttribute( name ),
				value = result + "",
				type = match[2],
				check = match[4];

			return result == null ?
				type === "!=" :
				type === "=" ?
				value === check :
				type === "*=" ?
				value.indexOf(check) >= 0 :
				type === "~=" ?
				(" " + value + " ").indexOf(check) >= 0 :
				!check ?
				value && result !== false :
				type === "!=" ?
				value !== check :
				type === "^=" ?
				value.indexOf(check) === 0 :
				type === "$=" ?
				value.substr(value.length - check.length) === check :
				type === "|=" ?
				value === check || value.substr(0, check.length + 1) === check + "-" :
				false;
		},

		POS: function( elem, match, i, array ) {
			var name = match[2],
				filter = Expr.setFilters[ name ];

			if ( filter ) {
				return filter( elem, i, match, array );
			}
		}
	}
};

var origPOS = Expr.match.POS,
	fescape = function(all, num){
		return "\\" + (num - 0 + 1);
	};

for ( var type in Expr.match ) {
	Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) );
	Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) );
}

var makeArray = function( array, results ) {
	array = Array.prototype.slice.call( array, 0 );

	if ( results ) {
		results.push.apply( results, array );
		return results;
	}
	
	return array;
};

// Perform a simple check to determine if the browser is capable of
// converting a NodeList to an array using builtin methods.
// Also verifies that the returned array holds DOM nodes
// (which is not the case in the Blackberry browser)
try {
	Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType;

// Provide a fallback method if it does not work
} catch( e ) {
	makeArray = function( array, results ) {
		var i = 0,
			ret = results || [];

		if ( toString.call(array) === "[object Array]" ) {
			Array.prototype.push.apply( ret, array );

		} else {
			if ( typeof array.length === "number" ) {
				for ( var l = array.length; i < l; i++ ) {
					ret.push( array[i] );
				}

			} else {
				for ( ; array[i]; i++ ) {
					ret.push( array[i] );
				}
			}
		}

		return ret;
	};
}

var sortOrder, siblingCheck;

if ( document.documentElement.compareDocumentPosition ) {
	sortOrder = function( a, b ) {
		if ( a === b ) {
			hasDuplicate = true;
			return 0;
		}

		if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {
			return a.compareDocumentPosition ? -1 : 1;
		}

		return a.compareDocumentPosition(b) & 4 ? -1 : 1;
	};

} else {
	sortOrder = function( a, b ) {
		// The nodes are identical, we can exit early
		if ( a === b ) {
			hasDuplicate = true;
			return 0;

		// Fallback to using sourceIndex (in IE) if it's available on both nodes
		} else if ( a.sourceIndex && b.sourceIndex ) {
			return a.sourceIndex - b.sourceIndex;
		}

		var al, bl,
			ap = [],
			bp = [],
			aup = a.parentNode,
			bup = b.parentNode,
			cur = aup;

		// If the nodes are siblings (or identical) we can do a quick check
		if ( aup === bup ) {
			return siblingCheck( a, b );

		// If no parents were found then the nodes are disconnected
		} else if ( !aup ) {
			return -1;

		} else if ( !bup ) {
			return 1;
		}

		// Otherwise they're somewhere else in the tree so we need
		// to build up a full list of the parentNodes for comparison
		while ( cur ) {
			ap.unshift( cur );
			cur = cur.parentNode;
		}

		cur = bup;

		while ( cur ) {
			bp.unshift( cur );
			cur = cur.parentNode;
		}

		al = ap.length;
		bl = bp.length;

		// Start walking down the tree looking for a discrepancy
		for ( var i = 0; i < al && i < bl; i++ ) {
			if ( ap[i] !== bp[i] ) {
				return siblingCheck( ap[i], bp[i] );
			}
		}

		// We ended someplace up the tree so do a sibling check
		return i === al ?
			siblingCheck( a, bp[i], -1 ) :
			siblingCheck( ap[i], b, 1 );
	};

	siblingCheck = function( a, b, ret ) {
		if ( a === b ) {
			return ret;
		}

		var cur = a.nextSibling;

		while ( cur ) {
			if ( cur === b ) {
				return -1;
			}

			cur = cur.nextSibling;
		}

		return 1;
	};
}

// Utility function for retreiving the text value of an array of DOM nodes
Sizzle.getText = function( elems ) {
	var ret = "", elem;

	for ( var i = 0; elems[i]; i++ ) {
		elem = elems[i];

		// Get the text from text nodes and CDATA nodes
		if ( elem.nodeType === 3 || elem.nodeType === 4 ) {
			ret += elem.nodeValue;

		// Traverse everything else, except comment nodes
		} else if ( elem.nodeType !== 8 ) {
			ret += Sizzle.getText( elem.childNodes );
		}
	}

	return ret;
};

// Check to see if the browser returns elements by name when
// querying by getElementById (and provide a workaround)
(function(){
	// We're going to inject a fake input element with a specified name
	var form = document.createElement("div"),
		id = "script" + (new Date()).getTime(),
		root = document.documentElement;

	form.innerHTML = "<a name='" + id + "'/>";

	// Inject it into the root element, check its status, and remove it quickly
	root.insertBefore( form, root.firstChild );

	// The workaround has to do additional checks after a getElementById
	// Which slows things down for other browsers (hence the branching)
	if ( document.getElementById( id ) ) {
		Expr.find.ID = function( match, context, isXML ) {
			if ( typeof context.getElementById !== "undefined" && !isXML ) {
				var m = context.getElementById(match[1]);

				return m ?
					m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ?
						[m] :
						undefined :
					[];
			}
		};

		Expr.filter.ID = function( elem, match ) {
			var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");

			return elem.nodeType === 1 && node && node.nodeValue === match;
		};
	}

	root.removeChild( form );

	// release memory in IE
	root = form = null;
})();

(function(){
	// Check to see if the browser returns only elements
	// when doing getElementsByTagName("*")

	// Create a fake element
	var div = document.createElement("div");
	div.appendChild( document.createComment("") );

	// Make sure no comments are found
	if ( div.getElementsByTagName("*").length > 0 ) {
		Expr.find.TAG = function( match, context ) {
			var results = context.getElementsByTagName( match[1] );

			// Filter out possible comments
			if ( match[1] === "*" ) {
				var tmp = [];

				for ( var i = 0; results[i]; i++ ) {
					if ( results[i].nodeType === 1 ) {
						tmp.push( results[i] );
					}
				}

				results = tmp;
			}

			return results;
		};
	}

	// Check to see if an attribute returns normalized href attributes
	div.innerHTML = "<a href='#'></a>";

	if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" &&
			div.firstChild.getAttribute("href") !== "#" ) {

		Expr.attrHandle.href = function( elem ) {
			return elem.getAttribute( "href", 2 );
		};
	}

	// release memory in IE
	div = null;
})();

if ( document.querySelectorAll ) {
	(function(){
		var oldSizzle = Sizzle,
			div = document.createElement("div"),
			id = "__sizzle__";

		div.innerHTML = "<p class='TEST'></p>";

		// Safari can't handle uppercase or unicode characters when
		// in quirks mode.
		if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
			return;
		}
	
		Sizzle = function( query, context, extra, seed ) {
			context = context || document;

			// Only use querySelectorAll on non-XML documents
			// (ID selectors don't work in non-HTML documents)
			if ( !seed && !Sizzle.isXML(context) ) {
				// See if we find a selector to speed up
				var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query );
				
				if ( match && (context.nodeType === 1 || context.nodeType === 9) ) {
					// Speed-up: Sizzle("TAG")
					if ( match[1] ) {
						return makeArray( context.getElementsByTagName( query ), extra );
					
					// Speed-up: Sizzle(".CLASS")
					} else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) {
						return makeArray( context.getElementsByClassName( match[2] ), extra );
					}
				}
				
				if ( context.nodeType === 9 ) {
					// Speed-up: Sizzle("body")
					// The body element only exists once, optimize finding it
					if ( query === "body" && context.body ) {
						return makeArray( [ context.body ], extra );
						
					// Speed-up: Sizzle("#ID")
					} else if ( match && match[3] ) {
						var elem = context.getElementById( match[3] );

						// Check parentNode to catch when Blackberry 4.6 returns
						// nodes that are no longer in the document #6963
						if ( elem && elem.parentNode ) {
							// Handle the case where IE and Opera return items
							// by name instead of ID
							if ( elem.id === match[3] ) {
								return makeArray( [ elem ], extra );
							}
							
						} else {
							return makeArray( [], extra );
						}
					}
					
					try {
						return makeArray( context.querySelectorAll(query), extra );
					} catch(qsaError) {}

				// qSA works strangely on Element-rooted queries
				// We can work around this by specifying an extra ID on the root
				// and working up from there (Thanks to Andrew Dupont for the technique)
				// IE 8 doesn't work on object elements
				} else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
					var oldContext = context,
						old = context.getAttribute( "id" ),
						nid = old || id,
						hasParent = context.parentNode,
						relativeHierarchySelector = /^\s*[+~]/.test( query );

					if ( !old ) {
						context.setAttribute( "id", nid );
					} else {
						nid = nid.replace( /'/g, "\\$&" );
					}
					if ( relativeHierarchySelector && hasParent ) {
						context = context.parentNode;
					}

					try {
						if ( !relativeHierarchySelector || hasParent ) {
							return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra );
						}

					} catch(pseudoError) {
					} finally {
						if ( !old ) {
							oldContext.removeAttribute( "id" );
						}
					}
				}
			}
		
			return oldSizzle(query, context, extra, seed);
		};

		for ( var prop in oldSizzle ) {
			Sizzle[ prop ] = oldSizzle[ prop ];
		}

		// release memory in IE
		div = null;
	})();
}

(function(){
	var html = document.documentElement,
		matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector;

	if ( matches ) {
		// Check to see if it's possible to do matchesSelector
		// on a disconnected node (IE 9 fails this)
		var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ),
			pseudoWorks = false;

		try {
			// This should fail with an exception
			// Gecko does not error, returns false instead
			matches.call( document.documentElement, "[test!='']:sizzle" );
	
		} catch( pseudoError ) {
			pseudoWorks = true;
		}

		Sizzle.matchesSelector = function( node, expr ) {
			// Make sure that attribute selectors are quoted
			expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']");

			if ( !Sizzle.isXML( node ) ) {
				try { 
					if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) {
						var ret = matches.call( node, expr );

						// IE 9's matchesSelector returns false on disconnected nodes
						if ( ret || !disconnectedMatch ||
								// As well, disconnected nodes are said to be in a document
								// fragment in IE 9, so check for that
								node.document && node.document.nodeType !== 11 ) {
							return ret;
						}
					}
				} catch(e) {}
			}

			return Sizzle(expr, null, null, [node]).length > 0;
		};
	}
})();

(function(){
	var div = document.createElement("div");

	div.innerHTML = "<div class='test e'></div><div class='test'></div>";

	// Opera can't find a second classname (in 9.6)
	// Also, make sure that getElementsByClassName actually exists
	if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) {
		return;
	}

	// Safari caches class attributes, doesn't catch changes (in 3.2)
	div.lastChild.className = "e";

	if ( div.getElementsByClassName("e").length === 1 ) {
		return;
	}
	
	Expr.order.splice(1, 0, "CLASS");
	Expr.find.CLASS = function( match, context, isXML ) {
		if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
			return context.getElementsByClassName(match[1]);
		}
	};

	// release memory in IE
	div = null;
})();

function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
	for ( var i = 0, l = checkSet.length; i < l; i++ ) {
		var elem = checkSet[i];

		if ( elem ) {
			var match = false;

			elem = elem[dir];

			while ( elem ) {
				if ( elem.sizcache === doneName ) {
					match = checkSet[elem.sizset];
					break;
				}

				if ( elem.nodeType === 1 && !isXML ){
					elem.sizcache = doneName;
					elem.sizset = i;
				}

				if ( elem.nodeName.toLowerCase() === cur ) {
					match = elem;
					break;
				}

				elem = elem[dir];
			}

			checkSet[i] = match;
		}
	}
}

function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
	for ( var i = 0, l = checkSet.length; i < l; i++ ) {
		var elem = checkSet[i];

		if ( elem ) {
			var match = false;
			
			elem = elem[dir];

			while ( elem ) {
				if ( elem.sizcache === doneName ) {
					match = checkSet[elem.sizset];
					break;
				}

				if ( elem.nodeType === 1 ) {
					if ( !isXML ) {
						elem.sizcache = doneName;
						elem.sizset = i;
					}

					if ( typeof cur !== "string" ) {
						if ( elem === cur ) {
							match = true;
							break;
						}

					} else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {
						match = elem;
						break;
					}
				}

				elem = elem[dir];
			}

			checkSet[i] = match;
		}
	}
}

if ( document.documentElement.contains ) {
	Sizzle.contains = function( a, b ) {
		return a !== b && (a.contains ? a.contains(b) : true);
	};

} else if ( document.documentElement.compareDocumentPosition ) {
	Sizzle.contains = function( a, b ) {
		return !!(a.compareDocumentPosition(b) & 16);
	};

} else {
	Sizzle.contains = function() {
		return false;
	};
}

Sizzle.isXML = function( elem ) {
	// documentElement is verified for cases where it doesn't yet exist
	// (such as loading iframes in IE - #4833) 
	var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement;

	return documentElement ? documentElement.nodeName !== "HTML" : false;
};

var posProcess = function( selector, context ) {
	var match,
		tmpSet = [],
		later = "",
		root = context.nodeType ? [context] : context;

	// Position selectors must be done after the filter
	// And so must :not(positional) so we move all PSEUDOs to the end
	while ( (match = Expr.match.PSEUDO.exec( selector )) ) {
		later += match[0];
		selector = selector.replace( Expr.match.PSEUDO, "" );
	}

	selector = Expr.relative[selector] ? selector + "*" : selector;

	for ( var i = 0, l = root.length; i < l; i++ ) {
		Sizzle( selector, root[i], tmpSet );
	}

	return Sizzle.filter( later, tmpSet );
};

// EXPOSE
jQuery.find = Sizzle;
jQuery.expr = Sizzle.selectors;
jQuery.expr[":"] = jQuery.expr.filters;
jQuery.unique = Sizzle.uniqueSort;
jQuery.text = Sizzle.getText;
jQuery.isXMLDoc = Sizzle.isXML;
jQuery.contains = Sizzle.contains;


})();


var runtil = /Until$/,
	rparentsprev = /^(?:parents|prevUntil|prevAll)/,
	// Note: This RegExp should be improved, or likely pulled from Sizzle
	rmultiselector = /,/,
	isSimple = /^.[^:#\[\.,]*$/,
	slice = Array.prototype.slice,
	POS = jQuery.expr.match.POS,
	// methods guaranteed to produce a unique set when starting from a unique set
	guaranteedUnique = {
		children: true,
		contents: true,
		next: true,
		prev: true
	};

jQuery.fn.extend({
	find: function( selector ) {
		var self = this,
			i, l;

		if ( typeof selector !== "string" ) {
			return jQuery( selector ).filter(function() {
				for ( i = 0, l = self.length; i < l; i++ ) {
					if ( jQuery.contains( self[ i ], this ) ) {
						return true;
					}
				}
			});
		}

		var ret = this.pushStack( "", "find", selector ),
			length, n, r;

		for ( i = 0, l = this.length; i < l; i++ ) {
			length = ret.length;
			jQuery.find( selector, this[i], ret );

			if ( i > 0 ) {
				// Make sure that the results are unique
				for ( n = length; n < ret.length; n++ ) {
					for ( r = 0; r < length; r++ ) {
						if ( ret[r] === ret[n] ) {
							ret.splice(n--, 1);
							break;
						}
					}
				}
			}
		}

		return ret;
	},

	has: function( target ) {
		var targets = jQuery( target );
		return this.filter(function() {
			for ( var i = 0, l = targets.length; i < l; i++ ) {
				if ( jQuery.contains( this, targets[i] ) ) {
					return true;
				}
			}
		});
	},

	not: function( selector ) {
		return this.pushStack( winnow(this, selector, false), "not", selector);
	},

	filter: function( selector ) {
		return this.pushStack( winnow(this, selector, true), "filter", selector );
	},

	is: function( selector ) {
		return !!selector && ( typeof selector === "string" ?
			jQuery.filter( selector, this ).length > 0 :
			this.filter( selector ).length > 0 );
	},

	closest: function( selectors, context ) {
		var ret = [], i, l, cur = this[0];
		
		// Array
		if ( jQuery.isArray( selectors ) ) {
			var match, selector,
				matches = {},
				level = 1;

			if ( cur && selectors.length ) {
				for ( i = 0, l = selectors.length; i < l; i++ ) {
					selector = selectors[i];

					if ( !matches[ selector ] ) {
						matches[ selector ] = POS.test( selector ) ?
							jQuery( selector, context || this.context ) :
							selector;
					}
				}

				while ( cur && cur.ownerDocument && cur !== context ) {
					for ( selector in matches ) {
						match = matches[ selector ];

						if ( match.jquery ? match.index( cur ) > -1 : jQuery( cur ).is( match ) ) {
							ret.push({ selector: selector, elem: cur, level: level });
						}
					}

					cur = cur.parentNode;
					level++;
				}
			}

			return ret;
		}

		// String
		var pos = POS.test( selectors ) || typeof selectors !== "string" ?
				jQuery( selectors, context || this.context ) :
				0;

		for ( i = 0, l = this.length; i < l; i++ ) {
			cur = this[i];

			while ( cur ) {
				if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) {
					ret.push( cur );
					break;

				} else {
					cur = cur.parentNode;
					if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) {
						break;
					}
				}
			}
		}

		ret = ret.length > 1 ? jQuery.unique( ret ) : ret;

		return this.pushStack( ret, "closest", selectors );
	},

	// Determine the position of an element within
	// the matched set of elements
	index: function( elem ) {
		if ( !elem || typeof elem === "string" ) {
			return jQuery.inArray( this[0],
				// If it receives a string, the selector is used
				// If it receives nothing, the siblings are used
				elem ? jQuery( elem ) : this.parent().children() );
		}
		// Locate the position of the desired element
		return jQuery.inArray(
			// If it receives a jQuery object, the first element is used
			elem.jquery ? elem[0] : elem, this );
	},

	add: function( selector, context ) {
		var set = typeof selector === "string" ?
				jQuery( selector, context ) :
				jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),
			all = jQuery.merge( this.get(), set );

		return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ?
			all :
			jQuery.unique( all ) );
	},

	andSelf: function() {
		return this.add( this.prevObject );
	}
});

// A painfully simple check to see if an element is disconnected
// from a document (should be improved, where feasible).
function isDisconnected( node ) {
	return !node || !node.parentNode || node.parentNode.nodeType === 11;
}

jQuery.each({
	parent: function( elem ) {
		var parent = elem.parentNode;
		return parent && parent.nodeType !== 11 ? parent : null;
	},
	parents: function( elem ) {
		return jQuery.dir( elem, "parentNode" );
	},
	parentsUntil: function( elem, i, until ) {
		return jQuery.dir( elem, "parentNode", until );
	},
	next: function( elem ) {
		return jQuery.nth( elem, 2, "nextSibling" );
	},
	prev: function( elem ) {
		return jQuery.nth( elem, 2, "previousSibling" );
	},
	nextAll: function( elem ) {
		return jQuery.dir( elem, "nextSibling" );
	},
	prevAll: function( elem ) {
		return jQuery.dir( elem, "previousSibling" );
	},
	nextUntil: function( elem, i, until ) {
		return jQuery.dir( elem, "nextSibling", until );
	},
	prevUntil: function( elem, i, until ) {
		return jQuery.dir( elem, "previousSibling", until );
	},
	siblings: function( elem ) {
		return jQuery.sibling( elem.parentNode.firstChild, elem );
	},
	children: function( elem ) {
		return jQuery.sibling( elem.firstChild );
	},
	contents: function( elem ) {
		return jQuery.nodeName( elem, "iframe" ) ?
			elem.contentDocument || elem.contentWindow.document :
			jQuery.makeArray( elem.childNodes );
	}
}, function( name, fn ) {
	jQuery.fn[ name ] = function( until, selector ) {
		var ret = jQuery.map( this, fn, until ),
			// The variable 'args' was introduced in
			// https://github.com/jquery/jquery/commit/52a0238
			// to work around a bug in Chrome 10 (Dev) and should be removed when the bug is fixed.
			// http://code.google.com/p/v8/issues/detail?id=1050
			args = slice.call(arguments);

		if ( !runtil.test( name ) ) {
			selector = until;
		}

		if ( selector && typeof selector === "string" ) {
			ret = jQuery.filter( selector, ret );
		}

		ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;

		if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {
			ret = ret.reverse();
		}

		return this.pushStack( ret, name, args.join(",") );
	};
});

jQuery.extend({
	filter: function( expr, elems, not ) {
		if ( not ) {
			expr = ":not(" + expr + ")";
		}

		return elems.length === 1 ?
			jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] :
			jQuery.find.matches(expr, elems);
	},

	dir: function( elem, dir, until ) {
		var matched = [],
			cur = elem[ dir ];

		while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
			if ( cur.nodeType === 1 ) {
				matched.push( cur );
			}
			cur = cur[dir];
		}
		return matched;
	},

	nth: function( cur, result, dir, elem ) {
		result = result || 1;
		var num = 0;

		for ( ; cur; cur = cur[dir] ) {
			if ( cur.nodeType === 1 && ++num === result ) {
				break;
			}
		}

		return cur;
	},

	sibling: function( n, elem ) {
		var r = [];

		for ( ; n; n = n.nextSibling ) {
			if ( n.nodeType === 1 && n !== elem ) {
				r.push( n );
			}
		}

		return r;
	}
});

// Implement the identical functionality for filter and not
function winnow( elements, qualifier, keep ) {

	// Can't pass null or undefined to indexOf in Firefox 4
	// Set to 0 to skip string check
	qualifier = qualifier || 0;

	if ( jQuery.isFunction( qualifier ) ) {
		return jQuery.grep(elements, function( elem, i ) {
			var retVal = !!qualifier.call( elem, i, elem );
			return retVal === keep;
		});

	} else if ( qualifier.nodeType ) {
		return jQuery.grep(elements, function( elem, i ) {
			return (elem === qualifier) === keep;
		});

	} else if ( typeof qualifier === "string" ) {
		var filtered = jQuery.grep(elements, function( elem ) {
			return elem.nodeType === 1;
		});

		if ( isSimple.test( qualifier ) ) {
			return jQuery.filter(qualifier, filtered, !keep);
		} else {
			qualifier = jQuery.filter( qualifier, filtered );
		}
	}

	return jQuery.grep(elements, function( elem, i ) {
		return (jQuery.inArray( elem, qualifier ) >= 0) === keep;
	});
}




var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g,
	rleadingWhitespace = /^\s+/,
	rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,
	rtagName = /<([\w:]+)/,
	rtbody = /<tbody/i,
	rhtml = /<|&#?\w+;/,
	rnocache = /<(?:script|object|embed|option|style)/i,
	// checked="checked" or checked
	rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
	rscriptType = /\/(java|ecma)script/i,
	rcleanScript = /^\s*<!(?:\[CDATA\[|\-\-)/,
	wrapMap = {
		option: [ 1, "<select multiple='multiple'>", "</select>" ],
		legend: [ 1, "<fieldset>", "</fieldset>" ],
		thead: [ 1, "<table>", "</table>" ],
		tr: [ 2, "<table><tbody>", "</tbody></table>" ],
		td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
		col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
		area: [ 1, "<map>", "</map>" ],
		_default: [ 0, "", "" ]
	};

wrapMap.optgroup = wrapMap.option;
wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
wrapMap.th = wrapMap.td;

// IE can't serialize <link> and <script> tags normally
if ( !jQuery.support.htmlSerialize ) {
	wrapMap._default = [ 1, "div<div>", "</div>" ];
}

jQuery.fn.extend({
	text: function( text ) {
		if ( jQuery.isFunction(text) ) {
			return this.each(function(i) {
				var self = jQuery( this );

				self.text( text.call(this, i, self.text()) );
			});
		}

		if ( typeof text !== "object" && text !== undefined ) {
			return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) );
		}

		return jQuery.text( this );
	},

	wrapAll: function( html ) {
		if ( jQuery.isFunction( html ) ) {
			return this.each(function(i) {
				jQuery(this).wrapAll( html.call(this, i) );
			});
		}

		if ( this[0] ) {
			// The elements to wrap the target around
			var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);

			if ( this[0].parentNode ) {
				wrap.insertBefore( this[0] );
			}

			wrap.map(function() {
				var elem = this;

				while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
					elem = elem.firstChild;
				}

				return elem;
			}).append( this );
		}

		return this;
	},

	wrapInner: function( html ) {
		if ( jQuery.isFunction( html ) ) {
			return this.each(function(i) {
				jQuery(this).wrapInner( html.call(this, i) );
			});
		}

		return this.each(function() {
			var self = jQuery( this ),
				contents = self.contents();

			if ( contents.length ) {
				contents.wrapAll( html );

			} else {
				self.append( html );
			}
		});
	},

	wrap: function( html ) {
		return this.each(function() {
			jQuery( this ).wrapAll( html );
		});
	},

	unwrap: function() {
		return this.parent().each(function() {
			if ( !jQuery.nodeName( this, "body" ) ) {
				jQuery( this ).replaceWith( this.childNodes );
			}
		}).end();
	},

	append: function() {
		return this.domManip(arguments, true, function( elem ) {
			if ( this.nodeType === 1 ) {
				this.appendChild( elem );
			}
		});
	},

	prepend: function() {
		return this.domManip(arguments, true, function( elem ) {
			if ( this.nodeType === 1 ) {
				this.insertBefore( elem, this.firstChild );
			}
		});
	},

	before: function() {
		if ( this[0] && this[0].parentNode ) {
			return this.domManip(arguments, false, function( elem ) {
				this.parentNode.insertBefore( elem, this );
			});
		} else if ( arguments.length ) {
			var set = jQuery(arguments[0]);
			set.push.apply( set, this.toArray() );
			return this.pushStack( set, "before", arguments );
		}
	},

	after: function() {
		if ( this[0] && this[0].parentNode ) {
			return this.domManip(arguments, false, function( elem ) {
				this.parentNode.insertBefore( elem, this.nextSibling );
			});
		} else if ( arguments.length ) {
			var set = this.pushStack( this, "after", arguments );
			set.push.apply( set, jQuery(arguments[0]).toArray() );
			return set;
		}
	},

	// keepData is for internal use only--do not document
	remove: function( selector, keepData ) {
		for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
			if ( !selector || jQuery.filter( selector, [ elem ] ).length ) {
				if ( !keepData && elem.nodeType === 1 ) {
					jQuery.cleanData( elem.getElementsByTagName("*") );
					jQuery.cleanData( [ elem ] );
				}

				if ( elem.parentNode ) {
					elem.parentNode.removeChild( elem );
				}
			}
		}

		return this;
	},

	empty: function() {
		for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
			// Remove element nodes and prevent memory leaks
			if ( elem.nodeType === 1 ) {
				jQuery.cleanData( elem.getElementsByTagName("*") );
			}

			// Remove any remaining nodes
			while ( elem.firstChild ) {
				elem.removeChild( elem.firstChild );
			}
		}

		return this;
	},

	clone: function( dataAndEvents, deepDataAndEvents ) {
		dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
		deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;

		return this.map( function () {
			return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
		});
	},

	html: function( value ) {
		if ( value === undefined ) {
			return this[0] && this[0].nodeType === 1 ?
				this[0].innerHTML.replace(rinlinejQuery, "") :
				null;

		// See if we can take a shortcut and just use innerHTML
		} else if ( typeof value === "string" && !rnocache.test( value ) &&
			(jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value )) &&
			!wrapMap[ (rtagName.exec( value ) || ["", ""])[1].toLowerCase() ] ) {

			value = value.replace(rxhtmlTag, "<$1></$2>");

			try {
				for ( var i = 0, l = this.length; i < l; i++ ) {
					// Remove element nodes and prevent memory leaks
					if ( this[i].nodeType === 1 ) {
						jQuery.cleanData( this[i].getElementsByTagName("*") );
						this[i].innerHTML = value;
					}
				}

			// If using innerHTML throws an exception, use the fallback method
			} catch(e) {
				this.empty().append( value );
			}

		} else if ( jQuery.isFunction( value ) ) {
			this.each(function(i){
				var self = jQuery( this );

				self.html( value.call(this, i, self.html()) );
			});

		} else {
			this.empty().append( value );
		}

		return this;
	},

	replaceWith: function( value ) {
		if ( this[0] && this[0].parentNode ) {
			// Make sure that the elements are removed from the DOM before they are inserted
			// this can help fix replacing a parent with child elements
			if ( jQuery.isFunction( value ) ) {
				return this.each(function(i) {
					var self = jQuery(this), old = self.html();
					self.replaceWith( value.call( this, i, old ) );
				});
			}

			if ( typeof value !== "string" ) {
				value = jQuery( value ).detach();
			}

			return this.each(function() {
				var next = this.nextSibling,
					parent = this.parentNode;

				jQuery( this ).remove();

				if ( next ) {
					jQuery(next).before( value );
				} else {
					jQuery(parent).append( value );
				}
			});
		} else {
			return this.length ?
				this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ) :
				this;
		}
	},

	detach: function( selector ) {
		return this.remove( selector, true );
	},

	domManip: function( args, table, callback ) {
		var results, first, fragment, parent,
			value = args[0],
			scripts = [];

		// We can't cloneNode fragments that contain checked, in WebKit
		if ( !jQuery.support.checkClone && arguments.length === 3 && typeof value === "string" && rchecked.test( value ) ) {
			return this.each(function() {
				jQuery(this).domManip( args, table, callback, true );
			});
		}

		if ( jQuery.isFunction(value) ) {
			return this.each(function(i) {
				var self = jQuery(this);
				args[0] = value.call(this, i, table ? self.html() : undefined);
				self.domManip( args, table, callback );
			});
		}

		if ( this[0] ) {
			parent = value && value.parentNode;

			// If we're in a fragment, just use that instead of building a new one
			if ( jQuery.support.parentNode && parent && parent.nodeType === 11 && parent.childNodes.length === this.length ) {
				results = { fragment: parent };

			} else {
				results = jQuery.buildFragment( args, this, scripts );
			}

			fragment = results.fragment;

			if ( fragment.childNodes.length === 1 ) {
				first = fragment = fragment.firstChild;
			} else {
				first = fragment.firstChild;
			}

			if ( first ) {
				table = table && jQuery.nodeName( first, "tr" );

				for ( var i = 0, l = this.length, lastIndex = l - 1; i < l; i++ ) {
					callback.call(
						table ?
							root(this[i], first) :
							this[i],
						// Make sure that we do not leak memory by inadvertently discarding
						// the original fragment (which might have attached data) instead of
						// using it; in addition, use the original fragment object for the last
						// item instead of first because it can end up being emptied incorrectly
						// in certain situations (Bug #8070).
						// Fragments from the fragment cache must always be cloned and never used
						// in place.
						results.cacheable || (l > 1 && i < lastIndex) ?
							jQuery.clone( fragment, true, true ) :
							fragment
					);
				}
			}

			if ( scripts.length ) {
				jQuery.each( scripts, evalScript );
			}
		}

		return this;
	}
});

function root( elem, cur ) {
	return jQuery.nodeName(elem, "table") ?
		(elem.getElementsByTagName("tbody")[0] ||
		elem.appendChild(elem.ownerDocument.createElement("tbody"))) :
		elem;
}

function cloneCopyEvent( src, dest ) {

	if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
		return;
	}

	var internalKey = jQuery.expando,
		oldData = jQuery.data( src ),
		curData = jQuery.data( dest, oldData );

	// Switch to use the internal data object, if it exists, for the next
	// stage of data copying
	if ( (oldData = oldData[ internalKey ]) ) {
		var events = oldData.events;
				curData = curData[ internalKey ] = jQuery.extend({}, oldData);

		if ( events ) {
			delete curData.handle;
			curData.events = {};

			for ( var type in events ) {
				for ( var i = 0, l = events[ type ].length; i < l; i++ ) {
					jQuery.event.add( dest, type + ( events[ type ][ i ].namespace ? "." : "" ) + events[ type ][ i ].namespace, events[ type ][ i ], events[ type ][ i ].data );
				}
			}
		}
	}
}

function cloneFixAttributes( src, dest ) {
	var nodeName;

	// We do not need to do anything for non-Elements
	if ( dest.nodeType !== 1 ) {
		return;
	}

	// clearAttributes removes the attributes, which we don't want,
	// but also removes the attachEvent events, which we *do* want
	if ( dest.clearAttributes ) {
		dest.clearAttributes();
	}

	// mergeAttributes, in contrast, only merges back on the
	// original attributes, not the events
	if ( dest.mergeAttributes ) {
		dest.mergeAttributes( src );
	}

	nodeName = dest.nodeName.toLowerCase();

	// IE6-8 fail to clone children inside object elements that use
	// the proprietary classid attribute value (rather than the type
	// attribute) to identify the type of content to display
	if ( nodeName === "object" ) {
		dest.outerHTML = src.outerHTML;

	} else if ( nodeName === "input" && (src.type === "checkbox" || src.type === "radio") ) {
		// IE6-8 fails to persist the checked state of a cloned checkbox
		// or radio button. Worse, IE6-7 fail to give the cloned element
		// a checked appearance if the defaultChecked value isn't also set
		if ( src.checked ) {
			dest.defaultChecked = dest.checked = src.checked;
		}

		// IE6-7 get confused and end up setting the value of a cloned
		// checkbox/radio button to an empty string instead of "on"
		if ( dest.value !== src.value ) {
			dest.value = src.value;
		}

	// IE6-8 fails to return the selected option to the default selected
	// state when cloning options
	} else if ( nodeName === "option" ) {
		dest.selected = src.defaultSelected;

	// IE6-8 fails to set the defaultValue to the correct value when
	// cloning other types of input fields
	} else if ( nodeName === "input" || nodeName === "textarea" ) {
		dest.defaultValue = src.defaultValue;
	}

	// Event data gets referenced instead of copied if the expando
	// gets copied too
	dest.removeAttribute( jQuery.expando );
}

jQuery.buildFragment = function( args, nodes, scripts ) {
	var fragment, cacheable, cacheresults, doc;

  // nodes may contain either an explicit document object,
  // a jQuery collection or context object.
  // If nodes[0] contains a valid object to assign to doc
  if ( nodes && nodes[0] ) {
    doc = nodes[0].ownerDocument || nodes[0];
  }

  // Ensure that an attr object doesn't incorrectly stand in as a document object
	// Chrome and Firefox seem to allow this to occur and will throw exception
	// Fixes #8950
	if ( !doc.createDocumentFragment ) {
		doc = document;
	}

	// Only cache "small" (1/2 KB) HTML strings that are associated with the main document
	// Cloning options loses the selected state, so don't cache them
	// IE 6 doesn't like it when you put <object> or <embed> elements in a fragment
	// Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache
	if ( args.length === 1 && typeof args[0] === "string" && args[0].length < 512 && doc === document &&
		args[0].charAt(0) === "<" && !rnocache.test( args[0] ) && (jQuery.support.checkClone || !rchecked.test( args[0] )) ) {

		cacheable = true;

		cacheresults = jQuery.fragments[ args[0] ];
		if ( cacheresults && cacheresults !== 1 ) {
			fragment = cacheresults;
		}
	}

	if ( !fragment ) {
		fragment = doc.createDocumentFragment();
		jQuery.clean( args, doc, fragment, scripts );
	}

	if ( cacheable ) {
		jQuery.fragments[ args[0] ] = cacheresults ? fragment : 1;
	}

	return { fragment: fragment, cacheable: cacheable };
};

jQuery.fragments = {};

jQuery.each({
	appendTo: "append",
	prependTo: "prepend",
	insertBefore: "before",
	insertAfter: "after",
	replaceAll: "replaceWith"
}, function( name, original ) {
	jQuery.fn[ name ] = function( selector ) {
		var ret = [],
			insert = jQuery( selector ),
			parent = this.length === 1 && this[0].parentNode;

		if ( parent && parent.nodeType === 11 && parent.childNodes.length === 1 && insert.length === 1 ) {
			insert[ original ]( this[0] );
			return this;

		} else {
			for ( var i = 0, l = insert.length; i < l; i++ ) {
				var elems = (i > 0 ? this.clone(true) : this).get();
				jQuery( insert[i] )[ original ]( elems );
				ret = ret.concat( elems );
			}

			return this.pushStack( ret, name, insert.selector );
		}
	};
});

function getAll( elem ) {
	if ( "getElementsByTagName" in elem ) {
		return elem.getElementsByTagName( "*" );

	} else if ( "querySelectorAll" in elem ) {
		return elem.querySelectorAll( "*" );

	} else {
		return [];
	}
}

// Used in clean, fixes the defaultChecked property
function fixDefaultChecked( elem ) {
	if ( elem.type === "checkbox" || elem.type === "radio" ) {
		elem.defaultChecked = elem.checked;
	}
}
// Finds all inputs and passes them to fixDefaultChecked
function findInputs( elem ) {
	if ( jQuery.nodeName( elem, "input" ) ) {
		fixDefaultChecked( elem );
	} else if ( "getElementsByTagName" in elem ) {
		jQuery.grep( elem.getElementsByTagName("input"), fixDefaultChecked );
	}
}

jQuery.extend({
	clone: function( elem, dataAndEvents, deepDataAndEvents ) {
		var clone = elem.cloneNode(true),
				srcElements,
				destElements,
				i;

		if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&
				(elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
			// IE copies events bound via attachEvent when using cloneNode.
			// Calling detachEvent on the clone will also remove the events
			// from the original. In order to get around this, we use some
			// proprietary methods to clear the events. Thanks to MooTools
			// guys for this hotness.

			cloneFixAttributes( elem, clone );

			// Using Sizzle here is crazy slow, so we use getElementsByTagName
			// instead
			srcElements = getAll( elem );
			destElements = getAll( clone );

			// Weird iteration because IE will replace the length property
			// with an element if you are cloning the body and one of the
			// elements on the page has a name or id of "length"
			for ( i = 0; srcElements[i]; ++i ) {
				cloneFixAttributes( srcElements[i], destElements[i] );
			}
		}

		// Copy the events from the original to the clone
		if ( dataAndEvents ) {
			cloneCopyEvent( elem, clone );

			if ( deepDataAndEvents ) {
				srcElements = getAll( elem );
				destElements = getAll( clone );

				for ( i = 0; srcElements[i]; ++i ) {
					cloneCopyEvent( srcElements[i], destElements[i] );
				}
			}
		}

		srcElements = destElements = null;

		// Return the cloned set
		return clone;
	},

	clean: function( elems, context, fragment, scripts ) {
		var checkScriptType;

		context = context || document;

		// !context.createElement fails in IE with an error but returns typeof 'object'
		if ( typeof context.createElement === "undefined" ) {
			context = context.ownerDocument || context[0] && context[0].ownerDocument || document;
		}

		var ret = [], j;

		for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
			if ( typeof elem === "number" ) {
				elem += "";
			}

			if ( !elem ) {
				continue;
			}

			// Convert html string into DOM nodes
			if ( typeof elem === "string" ) {
				if ( !rhtml.test( elem ) ) {
					elem = context.createTextNode( elem );
				} else {
					// Fix "XHTML"-style tags in all browsers
					elem = elem.replace(rxhtmlTag, "<$1></$2>");

					// Trim whitespace, otherwise indexOf won't work as expected
					var tag = (rtagName.exec( elem ) || ["", ""])[1].toLowerCase(),
						wrap = wrapMap[ tag ] || wrapMap._default,
						depth = wrap[0],
						div = context.createElement("div");

					// Go to html and back, then peel off extra wrappers
					div.innerHTML = wrap[1] + elem + wrap[2];

					// Move to the right depth
					while ( depth-- ) {
						div = div.lastChild;
					}

					// Remove IE's autoinserted <tbody> from table fragments
					if ( !jQuery.support.tbody ) {

						// String was a <table>, *may* have spurious <tbody>
						var hasBody = rtbody.test(elem),
							tbody = tag === "table" && !hasBody ?
								div.firstChild && div.firstChild.childNodes :

								// String was a bare <thead> or <tfoot>
								wrap[1] === "<table>" && !hasBody ?
									div.childNodes :
									[];

						for ( j = tbody.length - 1; j >= 0 ; --j ) {
							if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) {
								tbody[ j ].parentNode.removeChild( tbody[ j ] );
							}
						}
					}

					// IE completely kills leading whitespace when innerHTML is used
					if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
						div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild );
					}

					elem = div.childNodes;
				}
			}

			// Resets defaultChecked for any radios and checkboxes
			// about to be appended to the DOM in IE 6/7 (#8060)
			var len;
			if ( !jQuery.support.appendChecked ) {
				if ( elem[0] && typeof (len = elem.length) === "number" ) {
					for ( j = 0; j < len; j++ ) {
						findInputs( elem[j] );
					}
				} else {
					findInputs( elem );
				}
			}

			if ( elem.nodeType ) {
				ret.push( elem );
			} else {
				ret = jQuery.merge( ret, elem );
			}
		}

		if ( fragment ) {
			checkScriptType = function( elem ) {
				return !elem.type || rscriptType.test( elem.type );
			};
			for ( i = 0; ret[i]; i++ ) {
				if ( scripts && jQuery.nodeName( ret[i], "script" ) && (!ret[i].type || ret[i].type.toLowerCase() === "text/javascript") ) {
					scripts.push( ret[i].parentNode ? ret[i].parentNode.removeChild( ret[i] ) : ret[i] );

				} else {
					if ( ret[i].nodeType === 1 ) {
						var jsTags = jQuery.grep( ret[i].getElementsByTagName( "script" ), checkScriptType );

						ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) );
					}
					fragment.appendChild( ret[i] );
				}
			}
		}

		return ret;
	},

	cleanData: function( elems ) {
		var data, id, cache = jQuery.cache, internalKey = jQuery.expando, special = jQuery.event.special,
			deleteExpando = jQuery.support.deleteExpando;

		for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
			if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) {
				continue;
			}

			id = elem[ jQuery.expando ];

			if ( id ) {
				data = cache[ id ] && cache[ id ][ internalKey ];

				if ( data && data.events ) {
					for ( var type in data.events ) {
						if ( special[ type ] ) {
							jQuery.event.remove( elem, type );

						// This is a shortcut to avoid jQuery.event.remove's overhead
						} else {
							jQuery.removeEvent( elem, type, data.handle );
						}
					}

					// Null the DOM reference to avoid IE6/7/8 leak (#7054)
					if ( data.handle ) {
						data.handle.elem = null;
					}
				}

				if ( deleteExpando ) {
					delete elem[ jQuery.expando ];

				} else if ( elem.removeAttribute ) {
					elem.removeAttribute( jQuery.expando );
				}

				delete cache[ id ];
			}
		}
	}
});

function evalScript( i, elem ) {
	if ( elem.src ) {
		jQuery.ajax({
			url: elem.src,
			async: false,
			dataType: "script"
		});
	} else {
		jQuery.globalEval( ( elem.text || elem.textContent || elem.innerHTML || "" ).replace( rcleanScript, "/*$0*/" ) );
	}

	if ( elem.parentNode ) {
		elem.parentNode.removeChild( elem );
	}
}



var ralpha = /alpha\([^)]*\)/i,
	ropacity = /opacity=([^)]*)/,
	// fixed for IE9, see #8346
	rupper = /([A-Z]|^ms)/g,
	rnumpx = /^-?\d+(?:px)?$/i,
	rnum = /^-?\d/,
	rrelNum = /^[+\-]=/,
	rrelNumFilter = /[^+\-\.\de]+/g,

	cssShow = { position: "absolute", visibility: "hidden", display: "block" },
	cssWidth = [ "Left", "Right" ],
	cssHeight = [ "Top", "Bottom" ],
	curCSS,

	getComputedStyle,
	currentStyle;

jQuery.fn.css = function( name, value ) {
	// Setting 'undefined' is a no-op
	if ( arguments.length === 2 && value === undefined ) {
		return this;
	}

	return jQuery.access( this, name, value, true, function( elem, name, value ) {
		return value !== undefined ?
			jQuery.style( elem, name, value ) :
			jQuery.css( elem, name );
	});
};

jQuery.extend({
	// Add in style property hooks for overriding the default
	// behavior of getting and setting a style property
	cssHooks: {
		opacity: {
			get: function( elem, computed ) {
				if ( computed ) {
					// We should always get a number back from opacity
					var ret = curCSS( elem, "opacity", "opacity" );
					return ret === "" ? "1" : ret;

				} else {
					return elem.style.opacity;
				}
			}
		}
	},

	// Exclude the following css properties to add px
	cssNumber: {
		"fillOpacity": true,
		"fontWeight": true,
		"lineHeight": true,
		"opacity": true,
		"orphans": true,
		"widows": true,
		"zIndex": true,
		"zoom": true
	},

	// Add in properties whose names you wish to fix before
	// setting or getting the value
	cssProps: {
		// normalize float css property
		"float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat"
	},

	// Get and set the style property on a DOM Node
	style: function( elem, name, value, extra ) {
		// Don't set styles on text and comment nodes
		if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
			return;
		}

		// Make sure that we're working with the right name
		var ret, type, origName = jQuery.camelCase( name ),
			style = elem.style, hooks = jQuery.cssHooks[ origName ];

		name = jQuery.cssProps[ origName ] || origName;

		// Check if we're setting a value
		if ( value !== undefined ) {
			type = typeof value;

			// Make sure that NaN and null values aren't set. See: #7116
			if ( type === "number" && isNaN( value ) || value == null ) {
				return;
			}

			// convert relative number strings (+= or -=) to relative numbers. #7345
			if ( type === "string" && rrelNum.test( value ) ) {
				value = +value.replace( rrelNumFilter, "" ) + parseFloat( jQuery.css( elem, name ) );
				// Fixes bug #9237
				type = "number";
			}

			// If a number was passed in, add 'px' to the (except for certain CSS properties)
			if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
				value += "px";
			}

			// If a hook was provided, use that value, otherwise just set the specified value
			if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value )) !== undefined ) {
				// Wrapped to prevent IE from throwing errors when 'invalid' values are provided
				// Fixes bug #5509
				try {
					style[ name ] = value;
				} catch(e) {}
			}

		} else {
			// If a hook was provided get the non-computed value from there
			if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
				return ret;
			}

			// Otherwise just get the value from the style object
			return style[ name ];
		}
	},

	css: function( elem, name, extra ) {
		var ret, hooks;

		// Make sure that we're working with the right name
		name = jQuery.camelCase( name );
		hooks = jQuery.cssHooks[ name ];
		name = jQuery.cssProps[ name ] || name;

		// cssFloat needs a special treatment
		if ( name === "cssFloat" ) {
			name = "float";
		}

		// If a hook was provided get the computed value from there
		if ( hooks && "get" in hooks && (ret = hooks.get( elem, true, extra )) !== undefined ) {
			return ret;

		// Otherwise, if a way to get the computed value exists, use that
		} else if ( curCSS ) {
			return curCSS( elem, name );
		}
	},

	// A method for quickly swapping in/out CSS properties to get correct calculations
	swap: function( elem, options, callback ) {
		var old = {};

		// Remember the old values, and insert the new ones
		for ( var name in options ) {
			old[ name ] = elem.style[ name ];
			elem.style[ name ] = options[ name ];
		}

		callback.call( elem );

		// Revert the old values
		for ( name in options ) {
			elem.style[ name ] = old[ name ];
		}
	}
});

// DEPRECATED, Use jQuery.css() instead
jQuery.curCSS = jQuery.css;

jQuery.each(["height", "width"], function( i, name ) {
	jQuery.cssHooks[ name ] = {
		get: function( elem, computed, extra ) {
			var val;

			if ( computed ) {
				if ( elem.offsetWidth !== 0 ) {
					return getWH( elem, name, extra );
				} else {
					jQuery.swap( elem, cssShow, function() {
						val = getWH( elem, name, extra );
					});
				}

				return val;
			}
		},

		set: function( elem, value ) {
			if ( rnumpx.test( value ) ) {
				// ignore negative width and height values #1599
				value = parseFloat( value );

				if ( value >= 0 ) {
					return value + "px";
				}

			} else {
				return value;
			}
		}
	};
});

if ( !jQuery.support.opacity ) {
	jQuery.cssHooks.opacity = {
		get: function( elem, computed ) {
			// IE uses filters for opacity
			return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ?
				( parseFloat( RegExp.$1 ) / 100 ) + "" :
				computed ? "1" : "";
		},

		set: function( elem, value ) {
			var style = elem.style,
				currentStyle = elem.currentStyle;

			// IE has trouble with opacity if it does not have layout
			// Force it by setting the zoom level
			style.zoom = 1;

			// Set the alpha filter to set the opacity
			var opacity = jQuery.isNaN( value ) ?
				"" :
				"alpha(opacity=" + value * 100 + ")",
				filter = currentStyle && currentStyle.filter || style.filter || "";

			style.filter = ralpha.test( filter ) ?
				filter.replace( ralpha, opacity ) :
				filter + " " + opacity;
		}
	};
}

jQuery(function() {
	// This hook cannot be added until DOM ready because the support test
	// for it is not run until after DOM ready
	if ( !jQuery.support.reliableMarginRight ) {
		jQuery.cssHooks.marginRight = {
			get: function( elem, computed ) {
				// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
				// Work around by temporarily setting element display to inline-block
				var ret;
				jQuery.swap( elem, { "display": "inline-block" }, function() {
					if ( computed ) {
						ret = curCSS( elem, "margin-right", "marginRight" );
					} else {
						ret = elem.style.marginRight;
					}
				});
				return ret;
			}
		};
	}
});

if ( document.defaultView && document.defaultView.getComputedStyle ) {
	getComputedStyle = function( elem, name ) {
		var ret, defaultView, computedStyle;

		name = name.replace( rupper, "-$1" ).toLowerCase();

		if ( !(defaultView = elem.ownerDocument.defaultView) ) {
			return undefined;
		}

		if ( (computedStyle = defaultView.getComputedStyle( elem, null )) ) {
			ret = computedStyle.getPropertyValue( name );
			if ( ret === "" && !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) {
				ret = jQuery.style( elem, name );
			}
		}

		return ret;
	};
}

if ( document.documentElement.currentStyle ) {
	currentStyle = function( elem, name ) {
		var left,
			ret = elem.currentStyle && elem.currentStyle[ name ],
			rsLeft = elem.runtimeStyle && elem.runtimeStyle[ name ],
			style = elem.style;

		// From the awesome hack by Dean Edwards
		// http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291

		// If we're not dealing with a regular pixel number
		// but a number that has a weird ending, we need to convert it to pixels
		if ( !rnumpx.test( ret ) && rnum.test( ret ) ) {
			// Remember the original values
			left = style.left;

			// Put in the new values to get a computed value out
			if ( rsLeft ) {
				elem.runtimeStyle.left = elem.currentStyle.left;
			}
			style.left = name === "fontSize" ? "1em" : (ret || 0);
			ret = style.pixelLeft + "px";

			// Revert the changed values
			style.left = left;
			if ( rsLeft ) {
				elem.runtimeStyle.left = rsLeft;
			}
		}

		return ret === "" ? "auto" : ret;
	};
}

curCSS = getComputedStyle || currentStyle;

function getWH( elem, name, extra ) {

	// Start with offset property
	var val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
		which = name === "width" ? cssWidth : cssHeight;

	if ( val > 0 ) {
		if ( extra !== "border" ) {
			jQuery.each( which, function() {
				if ( !extra ) {
					val -= parseFloat( jQuery.css( elem, "padding" + this ) ) || 0;
				}
				if ( extra === "margin" ) {
					val += parseFloat( jQuery.css( elem, extra + this ) ) || 0;
				} else {
					val -= parseFloat( jQuery.css( elem, "border" + this + "Width" ) ) || 0;
				}
			});
		}

		return val + "px";
	}

	// Fall back to computed then uncomputed css if necessary
	val = curCSS( elem, name, name );
	if ( val < 0 || val == null ) {
		val = elem.style[ name ] || 0;
	}
	// Normalize "", auto, and prepare for extra
	val = parseFloat( val ) || 0;

	// Add padding, border, margin
	if ( extra ) {
		jQuery.each( which, function() {
			val += parseFloat( jQuery.css( elem, "padding" + this ) ) || 0;
			if ( extra !== "padding" ) {
				val += parseFloat( jQuery.css( elem, "border" + this + "Width" ) ) || 0;
			}
			if ( extra === "margin" ) {
				val += parseFloat( jQuery.css( elem, extra + this ) ) || 0;
			}
		});
	}

	return val + "px";
}

if ( jQuery.expr && jQuery.expr.filters ) {
	jQuery.expr.filters.hidden = function( elem ) {
		var width = elem.offsetWidth,
			height = elem.offsetHeight;

		return (width === 0 && height === 0) || (!jQuery.support.reliableHiddenOffsets && (elem.style.display || jQuery.css( elem, "display" )) === "none");
	};

	jQuery.expr.filters.visible = function( elem ) {
		return !jQuery.expr.filters.hidden( elem );
	};
}




var r20 = /%20/g,
	rbracket = /\[\]$/,
	rCRLF = /\r?\n/g,
	rhash = /#.*$/,
	rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
	rinput = /^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,
	// #7653, #8125, #8152: local protocol detection
	rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|widget):$/,
	rnoContent = /^(?:GET|HEAD)$/,
	rprotocol = /^\/\//,
	rquery = /\?/,
	rscript = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
	rselectTextarea = /^(?:select|textarea)/i,
	rspacesAjax = /\s+/,
	rts = /([?&])_=[^&]*/,
	rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,

	// Keep a copy of the old load method
	_load = jQuery.fn.load,

	/* Prefilters
	 * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
	 * 2) These are called:
	 *    - BEFORE asking for a transport
	 *    - AFTER param serialization (s.data is a string if s.processData is true)
	 * 3) key is the dataType
	 * 4) the catchall symbol "*" can be used
	 * 5) execution will start with transport dataType and THEN continue down to "*" if needed
	 */
	prefilters = {},

	/* Transports bindings
	 * 1) key is the dataType
	 * 2) the catchall symbol "*" can be used
	 * 3) selection will start with transport dataType and THEN go to "*" if needed
	 */
	transports = {},

	// Document location
	ajaxLocation,

	// Document location segments
	ajaxLocParts;

// #8138, IE may throw an exception when accessing
// a field from window.location if document.domain has been set
try {
	ajaxLocation = location.href;
} catch( e ) {
	// Use the href attribute of an A element
	// since IE will modify it given document.location
	ajaxLocation = document.createElement( "a" );
	ajaxLocation.href = "";
	ajaxLocation = ajaxLocation.href;
}

// Segment location into parts
ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];

// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
function addToPrefiltersOrTransports( structure ) {

	// dataTypeExpression is optional and defaults to "*"
	return function( dataTypeExpression, func ) {

		if ( typeof dataTypeExpression !== "string" ) {
			func = dataTypeExpression;
			dataTypeExpression = "*";
		}

		if ( jQuery.isFunction( func ) ) {
			var dataTypes = dataTypeExpression.toLowerCase().split( rspacesAjax ),
				i = 0,
				length = dataTypes.length,
				dataType,
				list,
				placeBefore;

			// For each dataType in the dataTypeExpression
			for(; i < length; i++ ) {
				dataType = dataTypes[ i ];
				// We control if we're asked to add before
				// any existing element
				placeBefore = /^\+/.test( dataType );
				if ( placeBefore ) {
					dataType = dataType.substr( 1 ) || "*";
				}
				list = structure[ dataType ] = structure[ dataType ] || [];
				// then we add to the structure accordingly
				list[ placeBefore ? "unshift" : "push" ]( func );
			}
		}
	};
}

// Base inspection function for prefilters and transports
function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR,
		dataType /* internal */, inspected /* internal */ ) {

	dataType = dataType || options.dataTypes[ 0 ];
	inspected = inspected || {};

	inspected[ dataType ] = true;

	var list = structure[ dataType ],
		i = 0,
		length = list ? list.length : 0,
		executeOnly = ( structure === prefilters ),
		selection;

	for(; i < length && ( executeOnly || !selection ); i++ ) {
		selection = list[ i ]( options, originalOptions, jqXHR );
		// If we got redirected to another dataType
		// we try there if executing only and not done already
		if ( typeof selection === "string" ) {
			if ( !executeOnly || inspected[ selection ] ) {
				selection = undefined;
			} else {
				options.dataTypes.unshift( selection );
				selection = inspectPrefiltersOrTransports(
						structure, options, originalOptions, jqXHR, selection, inspected );
			}
		}
	}
	// If we're only executing or nothing was selected
	// we try the catchall dataType if not done already
	if ( ( executeOnly || !selection ) && !inspected[ "*" ] ) {
		selection = inspectPrefiltersOrTransports(
				structure, options, originalOptions, jqXHR, "*", inspected );
	}
	// unnecessary when only executing (prefilters)
	// but it'll be ignored by the caller in that case
	return selection;
}

jQuery.fn.extend({
	load: function( url, params, callback ) {
		if ( typeof url !== "string" && _load ) {
			return _load.apply( this, arguments );

		// Don't do a request if no elements are being requested
		} else if ( !this.length ) {
			return this;
		}

		var off = url.indexOf( " " );
		if ( off >= 0 ) {
			var selector = url.slice( off, url.length );
			url = url.slice( 0, off );
		}

		// Default to a GET request
		var type = "GET";

		// If the second parameter was provided
		if ( params ) {
			// If it's a function
			if ( jQuery.isFunction( params ) ) {
				// We assume that it's the callback
				callback = params;
				params = undefined;

			// Otherwise, build a param string
			} else if ( typeof params === "object" ) {
				params = jQuery.param( params, jQuery.ajaxSettings.traditional );
				type = "POST";
			}
		}

		var self = this;

		// Request the remote document
		jQuery.ajax({
			url: url,
			type: type,
			dataType: "html",
			data: params,
			// Complete callback (responseText is used internally)
			complete: function( jqXHR, status, responseText ) {
				// Store the response as specified by the jqXHR object
				responseText = jqXHR.responseText;
				// If successful, inject the HTML into all the matched elements
				if ( jqXHR.isResolved() ) {
					// #4825: Get the actual response in case
					// a dataFilter is present in ajaxSettings
					jqXHR.done(function( r ) {
						responseText = r;
					});
					// See if a selector was specified
					self.html( selector ?
						// Create a dummy div to hold the results
						jQuery("<div>")
							// inject the contents of the document in, removing the scripts
							// to avoid any 'Permission Denied' errors in IE
							.append(responseText.replace(rscript, ""))

							// Locate the specified elements
							.find(selector) :

						// If not, just inject the full result
						responseText );
				}

				if ( callback ) {
					self.each( callback, [ responseText, status, jqXHR ] );
				}
			}
		});

		return this;
	},

	serialize: function() {
		return jQuery.param( this.serializeArray() );
	},

	serializeArray: function() {
		return this.map(function(){
			return this.elements ? jQuery.makeArray( this.elements ) : this;
		})
		.filter(function(){
			return this.name && !this.disabled &&
				( this.checked || rselectTextarea.test( this.nodeName ) ||
					rinput.test( this.type ) );
		})
		.map(function( i, elem ){
			var val = jQuery( this ).val();

			return val == null ?
				null :
				jQuery.isArray( val ) ?
					jQuery.map( val, function( val, i ){
						return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
					}) :
					{ name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
		}).get();
	}
});

// Attach a bunch of functions for handling common AJAX events
jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split( " " ), function( i, o ){
	jQuery.fn[ o ] = function( f ){
		return this.bind( o, f );
	};
});

jQuery.each( [ "get", "post" ], function( i, method ) {
	jQuery[ method ] = function( url, data, callback, type ) {
		// shift arguments if data argument was omitted
		if ( jQuery.isFunction( data ) ) {
			type = type || callback;
			callback = data;
			data = undefined;
		}

		return jQuery.ajax({
			type: method,
			url: url,
			data: data,
			success: callback,
			dataType: type
		});
	};
});

jQuery.extend({

	getScript: function( url, callback ) {
		return jQuery.get( url, undefined, callback, "script" );
	},

	getJSON: function( url, data, callback ) {
		return jQuery.get( url, data, callback, "json" );
	},

	// Creates a full fledged settings object into target
	// with both ajaxSettings and settings fields.
	// If target is omitted, writes into ajaxSettings.
	ajaxSetup: function ( target, settings ) {
		if ( !settings ) {
			// Only one parameter, we extend ajaxSettings
			settings = target;
			target = jQuery.extend( true, jQuery.ajaxSettings, settings );
		} else {
			// target was provided, we extend into it
			jQuery.extend( true, target, jQuery.ajaxSettings, settings );
		}
		// Flatten fields we don't want deep extended
		for( var field in { context: 1, url: 1 } ) {
			if ( field in settings ) {
				target[ field ] = settings[ field ];
			} else if( field in jQuery.ajaxSettings ) {
				target[ field ] = jQuery.ajaxSettings[ field ];
			}
		}
		return target;
	},

	ajaxSettings: {
		url: ajaxLocation,
		isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
		global: true,
		type: "GET",
		contentType: "application/x-www-form-urlencoded",
		processData: true,
		async: true,
		/*
		timeout: 0,
		data: null,
		dataType: null,
		username: null,
		password: null,
		cache: null,
		traditional: false,
		headers: {},
		*/

		accepts: {
			xml: "application/xml, text/xml",
			html: "text/html",
			text: "text/plain",
			json: "application/json, text/javascript",
			"*": "*/*"
		},

		contents: {
			xml: /xml/,
			html: /html/,
			json: /json/
		},

		responseFields: {
			xml: "responseXML",
			text: "responseText"
		},

		// List of data converters
		// 1) key format is "source_type destination_type" (a single space in-between)
		// 2) the catchall symbol "*" can be used for source_type
		converters: {

			// Convert anything to text
			"* text": window.String,

			// Text to html (true = no transformation)
			"text html": true,

			// Evaluate text as a json expression
			"text json": jQuery.parseJSON,

			// Parse text as xml
			"text xml": jQuery.parseXML
		}
	},

	ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
	ajaxTransport: addToPrefiltersOrTransports( transports ),

	// Main method
	ajax: function( url, options ) {

		// If url is an object, simulate pre-1.5 signature
		if ( typeof url === "object" ) {
			options = url;
			url = undefined;
		}

		// Force options to be an object
		options = options || {};

		var // Create the final options object
			s = jQuery.ajaxSetup( {}, options ),
			// Callbacks context
			callbackContext = s.context || s,
			// Context for global events
			// It's the callbackContext if one was provided in the options
			// and if it's a DOM node or a jQuery collection
			globalEventContext = callbackContext !== s &&
				( callbackContext.nodeType || callbackContext instanceof jQuery ) ?
						jQuery( callbackContext ) : jQuery.event,
			// Deferreds
			deferred = jQuery.Deferred(),
			completeDeferred = jQuery._Deferred(),
			// Status-dependent callbacks
			statusCode = s.statusCode || {},
			// ifModified key
			ifModifiedKey,
			// Headers (they are sent all at once)
			requestHeaders = {},
			requestHeadersNames = {},
			// Response headers
			responseHeadersString,
			responseHeaders,
			// transport
			transport,
			// timeout handle
			timeoutTimer,
			// Cross-domain detection vars
			parts,
			// The jqXHR state
			state = 0,
			// To know if global events are to be dispatched
			fireGlobals,
			// Loop variable
			i,
			// Fake xhr
			jqXHR = {

				readyState: 0,

				// Caches the header
				setRequestHeader: function( name, value ) {
					if ( !state ) {
						var lname = name.toLowerCase();
						name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
						requestHeaders[ name ] = value;
					}
					return this;
				},

				// Raw string
				getAllResponseHeaders: function() {
					return state === 2 ? responseHeadersString : null;
				},

				// Builds headers hashtable if needed
				getResponseHeader: function( key ) {
					var match;
					if ( state === 2 ) {
						if ( !responseHeaders ) {
							responseHeaders = {};
							while( ( match = rheaders.exec( responseHeadersString ) ) ) {
								responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
							}
						}
						match = responseHeaders[ key.toLowerCase() ];
					}
					return match === undefined ? null : match;
				},

				// Overrides response content-type header
				overrideMimeType: function( type ) {
					if ( !state ) {
						s.mimeType = type;
					}
					return this;
				},

				// Cancel the request
				abort: function( statusText ) {
					statusText = statusText || "abort";
					if ( transport ) {
						transport.abort( statusText );
					}
					done( 0, statusText );
					return this;
				}
			};

		// Callback for when everything is done
		// It is defined here because jslint complains if it is declared
		// at the end of the function (which would be more logical and readable)
		function done( status, statusText, responses, headers ) {

			// Called once
			if ( state === 2 ) {
				return;
			}
			
			// State is "done" now
			state = 2;

			// Clear timeout if it exists
			if ( timeoutTimer ) {
				clearTimeout( timeoutTimer );
			}

			// Dereference transport for early garbage collection
			// (no matter how long the jqXHR object will be used)
			transport = undefined;

			// Cache response headers
			responseHeadersString = headers || "";

			// Set readyState
			jqXHR.readyState = status ? 4 : 0;

			var isSuccess,
				success,
				error,
				response = responses ? ajaxHandleResponses( s, jqXHR, responses ) : undefined,
				lastModified,
				etag;

			// If successful, handle type chaining
			if ( status >= 200 && status < 300 || status === 304 ) {

				// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
				if ( s.ifModified ) {

					if ( ( lastModified = jqXHR.getResponseHeader( "Last-Modified" ) ) ) {
						jQuery.lastModified[ ifModifiedKey ] = lastModified;
					}
					if ( ( etag = jqXHR.getResponseHeader( "Etag" ) ) ) {
						jQuery.etag[ ifModifiedKey ] = etag;
					}
				}

				// If not modified
				if ( status === 304 ) {

					statusText = "notmodified";
					isSuccess = true;

				// If we have data
				} else {

					try {
						success = ajaxConvert( s, response );
						statusText = "success";
						isSuccess = true;
					} catch(e) {
						// We have a parsererror
						statusText = "parsererror";
						error = e;
					}
				}
			} else {
				// We extract error from statusText
				// then normalize statusText and status for non-aborts
				error = statusText;
				if( !statusText || status ) {
					statusText = "error";
					if ( status < 0 ) {
						status = 0;
					}
				}
			}

			// Set data for the fake xhr object
			jqXHR.status = status;
			jqXHR.statusText = statusText;

			// Success/Error
			if ( isSuccess ) {
				try {
					deferred.resolveWith(callbackContext, new Array(success, statusText, jqXHR) );
				} catch (err)	{
				}
			} else {
				deferred.rejectWith( callbackContext, new Array(jqXHR, statusText, error) );
			}

			// Status-dependent callbacks
			jqXHR.statusCode( statusCode );
			statusCode = undefined;

			if ( fireGlobals ) {
				globalEventContext.trigger( "ajax" + ( isSuccess ? "Success" : "Error" ),
						[ jqXHR, s, isSuccess ? success : error ] );
			}

			// Complete
			completeDeferred.resolveWith( callbackContext, [ jqXHR, statusText ] );

			if ( fireGlobals ) {
				globalEventContext.trigger( "ajaxComplete", [ jqXHR, s] );
				// Handle the global AJAX counter
				if ( !( --jQuery.active ) ) {
					jQuery.event.trigger( "ajaxStop" );
				}
			}
		}

		// Attach deferreds
		deferred.promise( jqXHR );
		jqXHR.success = jqXHR.done;
		jqXHR.error = jqXHR.fail;
		jqXHR.complete = completeDeferred.done;

		// Status-dependent callbacks
		jqXHR.statusCode = function( map ) {
			if ( map ) {
				var tmp;
				if ( state < 2 ) {
					for( tmp in map ) {
						statusCode[ tmp ] = [ statusCode[tmp], map[tmp] ];
					}
				} else {
					tmp = map[ jqXHR.status ];
					jqXHR.then( tmp, tmp );
				}
			}
			return this;
		};

		// Remove hash character (#7531: and string promotion)
		// Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
		// We also use the url parameter if available
		s.url = ( ( url || s.url ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );

		// Extract dataTypes list
		s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( rspacesAjax );

		// Determine if a cross-domain request is in order
		if ( s.crossDomain == null ) {
			parts = rurl.exec( s.url.toLowerCase() );
			s.crossDomain = !!( parts &&
				( parts[ 1 ] != ajaxLocParts[ 1 ] || parts[ 2 ] != ajaxLocParts[ 2 ] ||
					( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) !=
						( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) ) )
			);
		}

		// Convert data if not already a string
		if ( s.data && s.processData && typeof s.data !== "string" ) {
			s.data = jQuery.param( s.data, s.traditional );
		}

		// Apply prefilters
		inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );

		// If request was aborted inside a prefiler, stop there
		if ( state === 2 ) {
			return false;
		}

		// We can fire global events as of now if asked to
		fireGlobals = s.global;

		// Uppercase the type
		s.type = s.type.toUpperCase();

		// Determine if request has content
		s.hasContent = !rnoContent.test( s.type );

		// Watch for a new set of requests
		if ( fireGlobals && jQuery.active++ === 0 ) {
			jQuery.event.trigger( "ajaxStart" );
		}

		// More options handling for requests with no content
		if ( !s.hasContent ) {

			// If data is available, append data to url
			if ( s.data ) {
				s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data;
			}

			// Get ifModifiedKey before adding the anti-cache parameter
			ifModifiedKey = s.url;

			// Add anti-cache in url if needed
			if ( s.cache === false ) {

				var ts = jQuery.now(),
					// try replacing _= if it is there
					ret = s.url.replace( rts, "$1_=" + ts );

				// if nothing was replaced, add timestamp to the end
				s.url = ret + ( (ret === s.url ) ? ( rquery.test( s.url ) ? "&" : "?" ) + "_=" + ts : "" );
			}
		}

		// Set the correct header, if data is being sent
		if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
			jqXHR.setRequestHeader( "Content-Type", s.contentType );
		}

		// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
		if ( s.ifModified ) {
			ifModifiedKey = ifModifiedKey || s.url;
			if ( jQuery.lastModified[ ifModifiedKey ] ) {
				jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ ifModifiedKey ] );
			}
			if ( jQuery.etag[ ifModifiedKey ] ) {
				jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ ifModifiedKey ] );
			}
		}

		// Set the Accepts header for the server, depending on the dataType
		jqXHR.setRequestHeader(
			"Accept",
			s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
				s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", */*; q=0.01" : "" ) :
				s.accepts[ "*" ]
		);

		// Check for headers option
		for ( i in s.headers ) {
			jqXHR.setRequestHeader( i, s.headers[ i ] );
		}

		// Allow custom headers/mimetypes and early abort
		if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
				// Abort if not done already
				jqXHR.abort();
				return false;

		}

		// Install callbacks on deferreds
		for ( i in { success: 1, error: 1, complete: 1 } ) {
			jqXHR[ i ]( s[ i ] );
		}

		// Get transport
		transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );

		// If no transport, we auto-abort
		if ( !transport ) {
			done( -1, "No Transport" );
		} else {
			jqXHR.readyState = 1;
			// Send global event
			if ( fireGlobals ) {
				globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
			}
			// Timeout
			if ( s.async && s.timeout > 0 ) {
				timeoutTimer = setTimeout( function(){
					jqXHR.abort( "timeout" );
				}, s.timeout );
			}

			try {
				state = 1;
				transport.send( requestHeaders, done );
			} catch (e) {
				// Propagate exception as error if not done
				if ( status < 2 ) {
					done( -1, e );
				// Simply rethrow otherwise
				} else {
					jQuery.error( e );
				}
			}
		}

		return jqXHR;
	},

	// Serialize an array of form elements or a set of
	// key/values into a query string
	param: function( a, traditional ) {
		var s = [],
			add = function( key, value ) {
				// If value is a function, invoke it and return its value
				value = jQuery.isFunction( value ) ? value() : value;
				s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
			};

		// Set traditional to true for jQuery <= 1.3.2 behavior.
		if ( traditional === undefined ) {
			traditional = jQuery.ajaxSettings.traditional;
		}

		// If an array was passed in, assume that it is an array of form elements.
		if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
			// Serialize the form elements
			jQuery.each( a, function() {
				add( this.name, this.value );
			});

		} else {
			// If traditional, encode the "old" way (the way 1.3.2 or older
			// did it), otherwise encode params recursively.
			for ( var prefix in a ) {
				buildParams( prefix, a[ prefix ], traditional, add );
			}
		}

		// Return the resulting serialization
		return s.join( "&" ).replace( r20, "+" );
	}
});

function buildParams( prefix, obj, traditional, add ) {
	if ( jQuery.isArray( obj ) ) {
		// Serialize array item.
		jQuery.each( obj, function( i, v ) {
			if ( traditional || rbracket.test( prefix ) ) {
				// Treat each array item as a scalar.
				add( prefix, v );

			} else {
				// If array item is non-scalar (array or object), encode its
				// numeric index to resolve deserialization ambiguity issues.
				// Note that rack (as of 1.0.0) can't currently deserialize
				// nested arrays properly, and attempting to do so may cause
				// a server error. Possible fixes are to modify rack's
				// deserialization algorithm or to provide an option or flag
				// to force array serialization to be shallow.
				buildParams( prefix + "[" + ( typeof v === "object" || jQuery.isArray(v) ? i : "" ) + "]", v, traditional, add );
			}
		});

	} else if ( !traditional && obj != null && typeof obj === "object" ) {
		// Serialize object item.
		for ( var name in obj ) {
			buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
		}

	} else {
		// Serialize scalar item.
		add( prefix, obj );
	}
}

// This is still on the jQuery object... for now
// Want to move this to jQuery.ajax some day
jQuery.extend({

	// Counter for holding the number of active queries
	active: 0,

	// Last-Modified header cache for next request
	lastModified: {},
	etag: {}

});

/* Handles responses to an ajax request:
 * - sets all responseXXX fields accordingly
 * - finds the right dataType (mediates between content-type and expected dataType)
 * - returns the corresponding response
 */
function ajaxHandleResponses( s, jqXHR, responses ) {

	var contents = s.contents,
		dataTypes = s.dataTypes,
		responseFields = s.responseFields,
		ct,
		type,
		finalDataType,
		firstDataType;

	// Fill responseXXX fields
	for( type in responseFields ) {
		if ( type in responses ) {
			jqXHR[ responseFields[type] ] = responses[ type ];
		}
	}

	// Remove auto dataType and get content-type in the process
	while( dataTypes[ 0 ] === "*" ) {
		dataTypes.shift();
		if ( ct === undefined ) {
			ct = s.mimeType || jqXHR.getResponseHeader( "content-type" );
		}
	}

	// Check if we're dealing with a known content-type
	if ( ct ) {
		for ( type in contents ) {
			if ( contents[ type ] && contents[ type ].test( ct ) ) {
				dataTypes.unshift( type );
				break;
			}
		}
	}

	// Check to see if we have a response for the expected dataType
	if ( dataTypes[ 0 ] in responses ) {
		finalDataType = dataTypes[ 0 ];
	} else {
		// Try convertible dataTypes
		for ( type in responses ) {
			if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
				finalDataType = type;
				break;
			}
			if ( !firstDataType ) {
				firstDataType = type;
			}
		}
		// Or just use first one
		finalDataType = finalDataType || firstDataType;
	}

	// If we found a dataType
	// We add the dataType to the list if needed
	// and return the corresponding response
	if ( finalDataType ) {
		if ( finalDataType !== dataTypes[ 0 ] ) {
			dataTypes.unshift( finalDataType );
		}
		return responses[ finalDataType ];
	}
}

// Chain conversions given the request and the original response
function ajaxConvert( s, response ) {

	// Apply the dataFilter if provided
	if ( s.dataFilter ) {
		response = s.dataFilter( response, s.dataType );
	}

	var dataTypes = s.dataTypes,
		converters = {},
		i,
		key,
		length = dataTypes.length,
		tmp,
		// Current and previous dataTypes
		current = dataTypes[ 0 ],
		prev,
		// Conversion expression
		conversion,
		// Conversion function
		conv,
		// Conversion functions (transitive conversion)
		conv1,
		conv2;

	// For each dataType in the chain
	for( i = 1; i < length; i++ ) {

		// Create converters map
		// with lowercased keys
		if ( i === 1 ) {
			for( key in s.converters ) {
				if( typeof key === "string" ) {
					converters[ key.toLowerCase() ] = s.converters[ key ];
				}
			}
		}

		// Get the dataTypes
		prev = current;
		current = dataTypes[ i ];

		// If current is auto dataType, update it to prev
		if( current === "*" ) {
			current = prev;
		// If no auto and dataTypes are actually different
		} else if ( prev !== "*" && prev !== current ) {

			// Get the converter
			conversion = prev + " " + current;
			conv = converters[ conversion ] || converters[ "* " + current ];

			// If there is no direct converter, search transitively
			if ( !conv ) {
				conv2 = undefined;
				for( conv1 in converters ) {
					tmp = conv1.split( " " );
					if ( tmp[ 0 ] === prev || tmp[ 0 ] === "*" ) {
						conv2 = converters[ tmp[1] + " " + current ];
						if ( conv2 ) {
							conv1 = converters[ conv1 ];
							if ( conv1 === true ) {
								conv = conv2;
							} else if ( conv2 === true ) {
								conv = conv1;
							}
							break;
						}
					}
				}
			}
			// If we found no converter, dispatch an error
			if ( !( conv || conv2 ) ) {
				jQuery.error( "No conversion from " + conversion.replace(" "," to ") );
			}
			// If found converter is not an equivalence
			if ( conv !== true ) {
				// Convert with 1 or 2 converters accordingly
				response = conv ? conv( response ) : conv2( conv1(response) );
			}
		}
	}
	return response;
}




var jsc = jQuery.now(),
	jsre = /(\=)\?(&|$)|\?\?/i;

// Default jsonp settings
jQuery.ajaxSetup({
	jsonp: "callback",
	jsonpCallback: function() {
		return jQuery.expando + "_" + ( jsc++ );
	}
});

// Detect, normalize options and install callbacks for jsonp requests
jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {

	var inspectData = s.contentType === "application/x-www-form-urlencoded" &&
		( typeof s.data === "string" );

	if ( s.dataTypes[ 0 ] === "jsonp" ||
		s.jsonp !== false && ( jsre.test( s.url ) ||
				inspectData && jsre.test( s.data ) ) ) {

		var responseContainer,
			jsonpCallback = s.jsonpCallback =
				jQuery.isFunction( s.jsonpCallback ) ? s.jsonpCallback() : s.jsonpCallback,
			previous = window[ jsonpCallback ],
			url = s.url,
			data = s.data,
			replace = "$1" + jsonpCallback + "$2";

		if ( s.jsonp !== false ) {
			url = url.replace( jsre, replace );
			if ( s.url === url ) {
				if ( inspectData ) {
					data = data.replace( jsre, replace );
				}
				if ( s.data === data ) {
					// Add callback manually
					url += (/\?/.test( url ) ? "&" : "?") + s.jsonp + "=" + jsonpCallback;
				}
			}
		}

		s.url = url;
		s.data = data;

		// Install callback
		window[ jsonpCallback ] = function( response ) {
			responseContainer = [ response ];
		};

		// Clean-up function
		jqXHR.always(function() {
			// Set callback back to previous value
			window[ jsonpCallback ] = previous;
			// Call if it was a function and we have a response
			if ( responseContainer && jQuery.isFunction( previous ) ) {
				window[ jsonpCallback ]( responseContainer[ 0 ] );
			}
		});

		// Use data converter to retrieve json after script execution
		s.converters["script json"] = function() {
			if ( !responseContainer ) {
				jQuery.error( jsonpCallback + " was not called" );
			}
			return responseContainer[ 0 ];
		};

		// force json dataType
		s.dataTypes[ 0 ] = "json";

		// Delegate to script
		return "script";
	}
});




// Install script dataType
jQuery.ajaxSetup({
	accepts: {
		script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
	},
	contents: {
		script: /javascript|ecmascript/
	},
	converters: {
		"text script": function( text ) {
			jQuery.globalEval( text );
			return text;
		}
	}
});

// Handle cache's special case and global
jQuery.ajaxPrefilter( "script", function( s ) {
	if ( s.cache === undefined ) {
		s.cache = false;
	}
	if ( s.crossDomain ) {
		s.type = "GET";
		s.global = false;
	}
});

// Bind script tag hack transport
jQuery.ajaxTransport( "script", function(s) {

	// This transport only deals with cross domain requests
	if ( s.crossDomain ) {

		var script,
			head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement;

		return {

			send: function( _, callback ) {

				script = document.createElement( "script" );

				script.async = "async";

				if ( s.scriptCharset ) {
					script.charset = s.scriptCharset;
				}

				script.src = s.url;

				// Attach handlers for all browsers
				script.onload = script.onreadystatechange = function( _, isAbort ) {

					if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {

						// Handle memory leak in IE
						script.onload = script.onreadystatechange = null;

						// Remove the script
						if ( head && script.parentNode ) {
							head.removeChild( script );
						}

						// Dereference the script
						script = undefined;

						// Callback if not abort
						if ( !isAbort ) {
							callback( 200, "success" );
						}
					}
				};
				// Use insertBefore instead of appendChild  to circumvent an IE6 bug.
				// This arises when a base node is used (#2709 and #4378).
				head.insertBefore( script, head.firstChild );
			},

			abort: function() {
				if ( script ) {
					script.onload( 0, 1 );
				}
			}
		};
	}
});




var // #5280: Internet Explorer will keep connections alive if we don't abort on unload
	xhrOnUnloadAbort = window.ActiveXObject ? function() {
		// Abort all pending requests
		for ( var key in xhrCallbacks ) {
			xhrCallbacks[ key ]( 0, 1 );
		}
	} : false,
	xhrId = 0,
	xhrCallbacks;

// Functions to create xhrs
function createStandardXHR() {
	try {
		return new window.XMLHttpRequest();
	} catch( e ) {}
}

function createActiveXHR() {
	try {
		return new window.ActiveXObject( "Microsoft.XMLHTTP" );
	} catch( e ) {}
}

// Create the request object
// (This is still attached to ajaxSettings for backward compatibility)
jQuery.ajaxSettings.xhr = window.ActiveXObject ?
	/* Microsoft failed to properly
	 * implement the XMLHttpRequest in IE7 (can't request local files),
	 * so we use the ActiveXObject when it is available
	 * Additionally XMLHttpRequest can be disabled in IE7/IE8 so
	 * we need a fallback.
	 */
	function() {
		return !this.isLocal && createStandardXHR() || createActiveXHR();
	} :
	// For all other browsers, use the standard XMLHttpRequest object
	createStandardXHR;

// Determine support properties
(function( xhr ) {
	jQuery.extend( jQuery.support, {
		ajax: !!xhr,
		cors: !!xhr && ( "withCredentials" in xhr )
	});
})( jQuery.ajaxSettings.xhr() );

// Create transport if the browser can provide an xhr
if ( jQuery.support.ajax ) {

	jQuery.ajaxTransport(function( s ) {
		// Cross domain only allowed if supported through XMLHttpRequest
		if ( !s.crossDomain || jQuery.support.cors ) {

			var callback;

			return {
				send: function( headers, complete ) {

					// Get a new xhr
					var xhr = s.xhr(),
						handle,
						i;

					// Open the socket
					// Passing null username, generates a login popup on Opera (#2865)
					if ( s.username ) {
						xhr.open( s.type, s.url, s.async, s.username, s.password );
					} else {
						xhr.open( s.type, s.url, s.async );
					}

					// Apply custom fields if provided
					if ( s.xhrFields ) {
						for ( i in s.xhrFields ) {
							xhr[ i ] = s.xhrFields[ i ];
						}
					}

					// Override mime type if needed
					if ( s.mimeType && xhr.overrideMimeType ) {
						xhr.overrideMimeType( s.mimeType );
					}

					// X-Requested-With header
					// For cross-domain requests, seeing as conditions for a preflight are
					// akin to a jigsaw puzzle, we simply never set it to be sure.
					// (it can always be set on a per-request basis or even using ajaxSetup)
					// For same-domain requests, won't change header if already provided.
					if ( !s.crossDomain && !headers["X-Requested-With"] ) {
						headers[ "X-Requested-With" ] = "XMLHttpRequest";
					}

					// Need an extra try/catch for cross domain requests in Firefox 3
					try {
						for ( i in headers ) {
							xhr.setRequestHeader( i, headers[ i ] );
						}
					} catch( _ ) {}

					// Do send the request
					// This may raise an exception which is actually
					// handled in jQuery.ajax (so no try/catch here)
					xhr.send( ( s.hasContent && s.data ) || null );

					// Listener
					callback = function( _, isAbort ) {

						var status,
							statusText,
							responseHeaders,
							responses,
							xml;

						// Firefox throws exceptions when accessing properties
						// of an xhr when a network error occured
						// http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)
						try {
							
							// Was never called and is aborted or complete
							if ( callback && ( isAbort || xhr.readyState === 4 ) ) {

								// Only called once
								callback = undefined;

								// Do not keep as active anymore
								if ( handle ) {
									xhr.onreadystatechange = jQuery.noop;
									if ( xhrOnUnloadAbort ) {
										delete xhrCallbacks[ handle ];
									}
								}

								// If it's an abort
								if ( isAbort ) {
									// Abort it manually if needed
									if ( xhr.readyState !== 4 ) {
										xhr.abort();
									}
								} else {
									status = xhr.status;
									responseHeaders = xhr.getAllResponseHeaders();
									responses = {};
									xml = xhr.responseXML;

									// Construct response list
									if ( xml && xml.documentElement /* #4958 */ ) {
										responses.xml = xml;
									}
									responses.text = xhr.responseText;

									// Firefox throws an exception when accessing
									// statusText for faulty cross-domain requests
									try {
										statusText = xhr.statusText;
									} catch( e ) {
										// We normalize with Webkit giving an empty statusText
										statusText = "";
									}

									// Filter status for non standard behaviors

									// If the request is local and we have data: assume a success
									// (success with no data won't get notified, that's the best we
									// can do given current implementations)
									if ( !status && s.isLocal && !s.crossDomain ) {
										status = responses.text ? 200 : 404;
									// IE - #1450: sometimes returns 1223 when it should be 204
									} else if ( status === 1223 ) {
										status = 204;
									}
								}
							}
						} catch( firefoxAccessException ) {
							if ( !isAbort ) {
								complete( -1, firefoxAccessException );
							}
						}

						// Call complete if needed
						if ( responses ) {
							complete( status, statusText, responses, responseHeaders );
						}
					};

					// if we're in sync mode or it's in cache
					// and has been retrieved directly (IE6 & IE7)
					// we need to manually fire the callback
					if ( !s.async || xhr.readyState === 4 ) {
						callback();
					} else {
						handle = ++xhrId;
						if ( xhrOnUnloadAbort ) {
							// Create the active xhrs callbacks list if needed
							// and attach the unload handler
							if ( !xhrCallbacks ) {
								xhrCallbacks = {};
								jQuery( window ).unload( xhrOnUnloadAbort );
							}
							// Add to list of active xhrs callbacks
							xhrCallbacks[ handle ] = callback;
						}
						xhr.onreadystatechange = callback;
					}
				},

				abort: function() {
					if ( callback ) {
						callback(0,1);
					}
				}
			};
		}
	});
}




var elemdisplay = {},
	iframe, iframeDoc,
	rfxtypes = /^(?:toggle|show|hide)$/,
	rfxnum = /^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,
	timerId,
	fxAttrs = [
		// height animations
		[ "height", "marginTop", "marginBottom", "paddingTop", "paddingBottom" ],
		// width animations
		[ "width", "marginLeft", "marginRight", "paddingLeft", "paddingRight" ],
		// opacity animations
		[ "opacity" ]
	],
	fxNow,
	requestAnimationFrame = window.webkitRequestAnimationFrame ||
		window.mozRequestAnimationFrame ||
		window.oRequestAnimationFrame;

jQuery.fn.extend({
	show: function( speed, easing, callback ) {
		var elem, display;

		if ( speed || speed === 0 ) {
			return this.animate( genFx("show", 3), speed, easing, callback);

		} else {
			for ( var i = 0, j = this.length; i < j; i++ ) {
				elem = this[i];

				if ( elem.style ) {
					display = elem.style.display;

					// Reset the inline display of this element to learn if it is
					// being hidden by cascaded rules or not
					if ( !jQuery._data(elem, "olddisplay") && display === "none" ) {
						display = elem.style.display = "";
					}

					// Set elements which have been overridden with display: none
					// in a stylesheet to whatever the default browser style is
					// for such an element
					if ( display === "" && jQuery.css( elem, "display" ) === "none" ) {
						jQuery._data(elem, "olddisplay", defaultDisplay(elem.nodeName));
					}
				}
			}

			// Set the display of most of the elements in a second loop
			// to avoid the constant reflow
			for ( i = 0; i < j; i++ ) {
				elem = this[i];

				if ( elem.style ) {
					display = elem.style.display;

					if ( display === "" || display === "none" ) {
						elem.style.display = jQuery._data(elem, "olddisplay") || "";
					}
				}
			}

			return this;
		}
	},

	hide: function( speed, easing, callback ) {
		if ( speed || speed === 0 ) {
			return this.animate( genFx("hide", 3), speed, easing, callback);

		} else {
			for ( var i = 0, j = this.length; i < j; i++ ) {
				if ( this[i].style ) {
					var display = jQuery.css( this[i], "display" );

					if ( display !== "none" && !jQuery._data( this[i], "olddisplay" ) ) {
						jQuery._data( this[i], "olddisplay", display );
					}
				}
			}

			// Set the display of the elements in a second loop
			// to avoid the constant reflow
			for ( i = 0; i < j; i++ ) {
				if ( this[i].style ) {
					this[i].style.display = "none";
				}
			}

			return this;
		}
	},

	// Save the old toggle function
	_toggle: jQuery.fn.toggle,

	toggle: function( fn, fn2, callback ) {
		var bool = typeof fn === "boolean";

		if ( jQuery.isFunction(fn) && jQuery.isFunction(fn2) ) {
			this._toggle.apply( this, arguments );

		} else if ( fn == null || bool ) {
			this.each(function() {
				var state = bool ? fn : jQuery(this).is(":hidden");
				jQuery(this)[ state ? "show" : "hide" ]();
			});

		} else {
			this.animate(genFx("toggle", 3), fn, fn2, callback);
		}

		return this;
	},

	fadeTo: function( speed, to, easing, callback ) {
		return this.filter(":hidden").css("opacity", 0).show().end()
					.animate({opacity: to}, speed, easing, callback);
	},

	animate: function( prop, speed, easing, callback ) {
		var optall = jQuery.speed(speed, easing, callback);

		if ( jQuery.isEmptyObject( prop ) ) {
			return this.each( optall.complete, [ false ] );
		}

		// Do not change referenced properties as per-property easing will be lost
		prop = jQuery.extend( {}, prop );

		return this[ optall.queue === false ? "each" : "queue" ](function() {
			// XXX 'this' does not always have a nodeName when running the
			// test suite

			if ( optall.queue === false ) {
				jQuery._mark( this );
			}

			var opt = jQuery.extend( {}, optall ),
				isElement = this.nodeType === 1,
				hidden = isElement && jQuery(this).is(":hidden"),
				name, val, p,
				display, e,
				parts, start, end, unit;

			// will store per property easing and be used to determine when an animation is complete
			opt.animatedProperties = {};

			for ( p in prop ) {

				// property name normalization
				name = jQuery.camelCase( p );
				if ( p !== name ) {
					prop[ name ] = prop[ p ];
					delete prop[ p ];
				}

				val = prop[ name ];

				// easing resolution: per property > opt.specialEasing > opt.easing > 'swing' (default)
				if ( jQuery.isArray( val ) ) {
					opt.animatedProperties[ name ] = val[ 1 ];
					val = prop[ name ] = val[ 0 ];
				} else {
					opt.animatedProperties[ name ] = opt.specialEasing && opt.specialEasing[ name ] || opt.easing || 'swing';
				}

				if ( val === "hide" && hidden || val === "show" && !hidden ) {
					return opt.complete.call( this );
				}

				if ( isElement && ( name === "height" || name === "width" ) ) {
					// Make sure that nothing sneaks out
					// Record all 3 overflow attributes because IE does not
					// change the overflow attribute when overflowX and
					// overflowY are set to the same value
					opt.overflow = [ this.style.overflow, this.style.overflowX, this.style.overflowY ];

					// Set display property to inline-block for height/width
					// animations on inline elements that are having width/height
					// animated
					if ( jQuery.css( this, "display" ) === "inline" &&
							jQuery.css( this, "float" ) === "none" ) {
						if ( !jQuery.support.inlineBlockNeedsLayout ) {
							this.style.display = "inline-block";

						} else {
							display = defaultDisplay( this.nodeName );

							// inline-level elements accept inline-block;
							// block-level elements need to be inline with layout
							if ( display === "inline" ) {
								this.style.display = "inline-block";

							} else {
								this.style.display = "inline";
								this.style.zoom = 1;
							}
						}
					}
				}
			}

			if ( opt.overflow != null ) {
				this.style.overflow = "hidden";
			}

			for ( p in prop ) {
				e = new jQuery.fx( this, opt, p );
				val = prop[ p ];

				if ( rfxtypes.test(val) ) {
					e[ val === "toggle" ? hidden ? "show" : "hide" : val ]();

				} else {
					parts = rfxnum.exec( val );
					start = e.cur();

					if ( parts ) {
						end = parseFloat( parts[2] );
						unit = parts[3] || ( jQuery.cssNumber[ p ] ? "" : "px" );

						// We need to compute starting value
						if ( unit !== "px" ) {
							jQuery.style( this, p, (end || 1) + unit);
							start = ((end || 1) / e.cur()) * start;
							jQuery.style( this, p, start + unit);
						}

						// If a +=/-= token was provided, we're doing a relative animation
						if ( parts[1] ) {
							end = ( (parts[ 1 ] === "-=" ? -1 : 1) * end ) + start;
						}

						e.custom( start, end, unit );

					} else {
						e.custom( start, val, "" );
					}
				}
			}

			// For JS strict compliance
			return true;
		});
	},

	stop: function( clearQueue, gotoEnd ) {
		if ( clearQueue ) {
			this.queue([]);
		}

		this.each(function() {
			var timers = jQuery.timers,
				i = timers.length;
			// clear marker counters if we know they won't be
			if ( !gotoEnd ) {
				jQuery._unmark( true, this );
			}
			while ( i-- ) {
				if ( timers[i].elem === this ) {
					if (gotoEnd) {
						// force the next step to be the last
						timers[i](true);
					}

					timers.splice(i, 1);
				}
			}
		});

		// start the next in the queue if the last step wasn't forced
		if ( !gotoEnd ) {
			this.dequeue();
		}

		return this;
	}

});

// Animations created synchronously will run synchronously
function createFxNow() {
	setTimeout( clearFxNow, 0 );
	return ( fxNow = jQuery.now() );
}

function clearFxNow() {
	fxNow = undefined;
}

// Generate parameters to create a standard animation
function genFx( type, num ) {
	var obj = {};

	jQuery.each( fxAttrs.concat.apply([], fxAttrs.slice(0,num)), function() {
		obj[ this ] = type;
	});

	return obj;
}

// Generate shortcuts for custom animations
jQuery.each({
	slideDown: genFx("show", 1),
	slideUp: genFx("hide", 1),
	slideToggle: genFx("toggle", 1),
	fadeIn: { opacity: "show" },
	fadeOut: { opacity: "hide" },
	fadeToggle: { opacity: "toggle" }
}, function( name, props ) {
	jQuery.fn[ name ] = function( speed, easing, callback ) {
		return this.animate( props, speed, easing, callback );
	};
});

jQuery.extend({
	speed: function( speed, easing, fn ) {
		var opt = speed && typeof speed === "object" ? jQuery.extend({}, speed) : {
			complete: fn || !fn && easing ||
				jQuery.isFunction( speed ) && speed,
			duration: speed,
			easing: fn && easing || easing && !jQuery.isFunction(easing) && easing
		};

		opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
			opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[opt.duration] : jQuery.fx.speeds._default;

		// Queueing
		opt.old = opt.complete;
		opt.complete = function( noUnmark ) {
			if ( jQuery.isFunction( opt.old ) ) {
				opt.old.call( this );
			}

			if ( opt.queue !== false ) {
				jQuery.dequeue( this );
			} else if ( noUnmark !== false ) {
				jQuery._unmark( this );
			}
		};

		return opt;
	},

	easing: {
		linear: function( p, n, firstNum, diff ) {
			return firstNum + diff * p;
		},
		swing: function( p, n, firstNum, diff ) {
			return ((-Math.cos(p*Math.PI)/2) + 0.5) * diff + firstNum;
		}
	},

	timers: [],

	fx: function( elem, options, prop ) {
		this.options = options;
		this.elem = elem;
		this.prop = prop;

		options.orig = options.orig || {};
	}

});

jQuery.fx.prototype = {
	// Simple function for setting a style value
	update: function() {
		if ( this.options.step ) {
			this.options.step.call( this.elem, this.now, this );
		}

		(jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this );
	},

	// Get the current size
	cur: function() {
		if ( this.elem[this.prop] != null && (!this.elem.style || this.elem.style[this.prop] == null) ) {
			return this.elem[ this.prop ];
		}

		var parsed,
			r = jQuery.css( this.elem, this.prop );
		// Empty strings, null, undefined and "auto" are converted to 0,
		// complex values such as "rotate(1rad)" are returned as is,
		// simple values such as "10px" are parsed to Float.
		return isNaN( parsed = parseFloat( r ) ) ? !r || r === "auto" ? 0 : r : parsed;
	},

	// Start an animation from one number to another
	custom: function( from, to, unit ) {
		var self = this,
			fx = jQuery.fx,
			raf;

		this.startTime = fxNow || createFxNow();
		this.start = from;
		this.end = to;
		this.unit = unit || this.unit || ( jQuery.cssNumber[ this.prop ] ? "" : "px" );
		this.now = this.start;
		this.pos = this.state = 0;

		function t( gotoEnd ) {
			return self.step(gotoEnd);
		}

		t.elem = this.elem;

		if ( t() && jQuery.timers.push(t) && !timerId ) {
			// Use requestAnimationFrame instead of setInterval if available
			if ( requestAnimationFrame ) {
				timerId = true;
				raf = function() {
					// When timerId gets set to null at any point, this stops
					if ( timerId ) {
						requestAnimationFrame( raf );
						fx.tick();
					}
				};
				requestAnimationFrame( raf );
			} else {
				timerId = setInterval( fx.tick, fx.interval );
			}
		}
	},

	// Simple 'show' function
	show: function() {
		// Remember where we started, so that we can go back to it later
		this.options.orig[this.prop] = jQuery.style( this.elem, this.prop );
		this.options.show = true;

		// Begin the animation
		// Make sure that we start at a small width/height to avoid any
		// flash of content
		this.custom(this.prop === "width" || this.prop === "height" ? 1 : 0, this.cur());

		// Start by showing the element
		jQuery( this.elem ).show();
	},

	// Simple 'hide' function
	hide: function() {
		// Remember where we started, so that we can go back to it later
		this.options.orig[this.prop] = jQuery.style( this.elem, this.prop );
		this.options.hide = true;

		// Begin the animation
		this.custom(this.cur(), 0);
	},

	// Each step of an animation
	step: function( gotoEnd ) {
		var t = fxNow || createFxNow(),
			done = true,
			elem = this.elem,
			options = this.options,
			i, n;

		if ( gotoEnd || t >= options.duration + this.startTime ) {
			this.now = this.end;
			this.pos = this.state = 1;
			this.update();

			options.animatedProperties[ this.prop ] = true;

			for ( i in options.animatedProperties ) {
				if ( options.animatedProperties[i] !== true ) {
					done = false;
				}
			}

			if ( done ) {
				// Reset the overflow
				if ( options.overflow != null && !jQuery.support.shrinkWrapBlocks ) {

					jQuery.each( [ "", "X", "Y" ], function (index, value) {
						elem.style[ "overflow" + value ] = options.overflow[index];
					});
				}

				// Hide the element if the "hide" operation was done
				if ( options.hide ) {
					jQuery(elem).hide();
				}

				// Reset the properties, if the item has been hidden or shown
				if ( options.hide || options.show ) {
					for ( var p in options.animatedProperties ) {
						jQuery.style( elem, p, options.orig[p] );
					}
				}

				// Execute the complete function
				options.complete.call( elem );
			}

			return false;

		} else {
			// classical easing cannot be used with an Infinity duration
			if ( options.duration == Infinity ) {
				this.now = t;
			} else {
				n = t - this.startTime;
				this.state = n / options.duration;

				// Perform the easing function, defaults to swing
				this.pos = jQuery.easing[ options.animatedProperties[ this.prop ] ]( this.state, n, 0, 1, options.duration );
				this.now = this.start + ((this.end - this.start) * this.pos);
			}
			// Perform the next step of the animation
			this.update();
		}

		return true;
	}
};

jQuery.extend( jQuery.fx, {
	tick: function() {
		for ( var timers = jQuery.timers, i = 0 ; i < timers.length ; ++i ) {
			if ( !timers[i]() ) {
				timers.splice(i--, 1);
			}
		}

		if ( !timers.length ) {
			jQuery.fx.stop();
		}
	},

	interval: 13,

	stop: function() {
		clearInterval( timerId );
		timerId = null;
	},

	speeds: {
		slow: 600,
		fast: 200,
		// Default speed
		_default: 400
	},

	step: {
		opacity: function( fx ) {
			jQuery.style( fx.elem, "opacity", fx.now );
		},

		_default: function( fx ) {
			if ( fx.elem.style && fx.elem.style[ fx.prop ] != null ) {
				fx.elem.style[ fx.prop ] = (fx.prop === "width" || fx.prop === "height" ? Math.max(0, fx.now) : fx.now) + fx.unit;
			} else {
				fx.elem[ fx.prop ] = fx.now;
			}
		}
	}
});

if ( jQuery.expr && jQuery.expr.filters ) {
	jQuery.expr.filters.animated = function( elem ) {
		return jQuery.grep(jQuery.timers, function( fn ) {
			return elem === fn.elem;
		}).length;
	};
}

// Try to restore the default display value of an element
function defaultDisplay( nodeName ) {

	if ( !elemdisplay[ nodeName ] ) {

		var body = document.body,
			elem = jQuery( "<" + nodeName + ">" ).appendTo( body ),
			display = elem.css( "display" );

		elem.remove();

		// If the simple way fails,
		// get element's real default display by attaching it to a temp iframe
		if ( display === "none" || display === "" ) {
			// No iframe to use yet, so create it
			if ( !iframe ) {
				iframe = document.createElement( "iframe" );
				iframe.frameBorder = iframe.width = iframe.height = 0;
			}

			body.appendChild( iframe );

			// Create a cacheable copy of the iframe document on first call.
			// IE and Opera will allow us to reuse the iframeDoc without re-writing the fake HTML
			// document to it; WebKit & Firefox won't allow reusing the iframe document.
			if ( !iframeDoc || !iframe.createElement ) {
				iframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document;
				iframeDoc.write( ( document.compatMode === "CSS1Compat" ? "<!doctype html>" : "" ) + "<html><body>" );
				iframeDoc.close();
			}

			elem = iframeDoc.createElement( nodeName );

			iframeDoc.body.appendChild( elem );

			display = jQuery.css( elem, "display" );

			body.removeChild( iframe );
		}

		// Store the correct default display
		elemdisplay[ nodeName ] = display;
	}

	return elemdisplay[ nodeName ];
}




var rtable = /^t(?:able|d|h)$/i,
	rroot = /^(?:body|html)$/i;

if ( "getBoundingClientRect" in document.documentElement ) {
	jQuery.fn.offset = function( options ) {
		var elem = this[0], box;

		if ( options ) {
			return this.each(function( i ) {
				jQuery.offset.setOffset( this, options, i );
			});
		}

		if ( !elem || !elem.ownerDocument ) {
			return null;
		}

		if ( elem === elem.ownerDocument.body ) {
			return jQuery.offset.bodyOffset( elem );
		}

		try {
			box = elem.getBoundingClientRect();
		} catch(e) {}

		var doc = elem.ownerDocument,
			docElem = doc.documentElement;

		// Make sure we're not dealing with a disconnected DOM node
		if ( !box || !jQuery.contains( docElem, elem ) ) {
			return box ? { top: box.top, left: box.left } : { top: 0, left: 0 };
		}

		var body = doc.body,
			win = getWindow(doc),
			clientTop  = docElem.clientTop  || body.clientTop  || 0,
			clientLeft = docElem.clientLeft || body.clientLeft || 0,
			scrollTop  = win.pageYOffset || jQuery.support.boxModel && docElem.scrollTop  || body.scrollTop,
			scrollLeft = win.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft,
			top  = box.top  + scrollTop  - clientTop,
			left = box.left + scrollLeft - clientLeft;

		return { top: top, left: left };
	};

} else {
	jQuery.fn.offset = function( options ) {
		var elem = this[0];

		if ( options ) {
			return this.each(function( i ) {
				jQuery.offset.setOffset( this, options, i );
			});
		}

		if ( !elem || !elem.ownerDocument ) {
			return null;
		}

		if ( elem === elem.ownerDocument.body ) {
			return jQuery.offset.bodyOffset( elem );
		}

		jQuery.offset.initialize();

		var computedStyle,
			offsetParent = elem.offsetParent,
			prevOffsetParent = elem,
			doc = elem.ownerDocument,
			docElem = doc.documentElement,
			body = doc.body,
			defaultView = doc.defaultView,
			prevComputedStyle = defaultView ? defaultView.getComputedStyle( elem, null ) : elem.currentStyle,
			top = elem.offsetTop,
			left = elem.offsetLeft;

		while ( (elem = elem.parentNode) && elem !== body && elem !== docElem ) {
			if ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === "fixed" ) {
				break;
			}

			computedStyle = defaultView ? defaultView.getComputedStyle(elem, null) : elem.currentStyle;
			top  -= elem.scrollTop;
			left -= elem.scrollLeft;

			if ( elem === offsetParent ) {
				top  += elem.offsetTop;
				left += elem.offsetLeft;

				if ( jQuery.offset.doesNotAddBorder && !(jQuery.offset.doesAddBorderForTableAndCells && rtable.test(elem.nodeName)) ) {
					top  += parseFloat( computedStyle.borderTopWidth  ) || 0;
					left += parseFloat( computedStyle.borderLeftWidth ) || 0;
				}

				prevOffsetParent = offsetParent;
				offsetParent = elem.offsetParent;
			}

			if ( jQuery.offset.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== "visible" ) {
				top  += parseFloat( computedStyle.borderTopWidth  ) || 0;
				left += parseFloat( computedStyle.borderLeftWidth ) || 0;
			}

			prevComputedStyle = computedStyle;
		}

		if ( prevComputedStyle.position === "relative" || prevComputedStyle.position === "static" ) {
			top  += body.offsetTop;
			left += body.offsetLeft;
		}

		if ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === "fixed" ) {
			top  += Math.max( docElem.scrollTop, body.scrollTop );
			left += Math.max( docElem.scrollLeft, body.scrollLeft );
		}

		return { top: top, left: left };
	};
}

jQuery.offset = {
	initialize: function() {
		var body = document.body, container = document.createElement("div"), innerDiv, checkDiv, table, td, bodyMarginTop = parseFloat( jQuery.css(body, "marginTop") ) || 0,
			html = "<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";

		jQuery.extend( container.style, { position: "absolute", top: 0, left: 0, margin: 0, border: 0, width: "1px", height: "1px", visibility: "hidden" } );

		container.innerHTML = html;
		body.insertBefore( container, body.firstChild );
		innerDiv = container.firstChild;
		checkDiv = innerDiv.firstChild;
		td = innerDiv.nextSibling.firstChild.firstChild;

		this.doesNotAddBorder = (checkDiv.offsetTop !== 5);
		this.doesAddBorderForTableAndCells = (td.offsetTop === 5);

		checkDiv.style.position = "fixed";
		checkDiv.style.top = "20px";

		// safari subtracts parent border width here which is 5px
		this.supportsFixedPosition = (checkDiv.offsetTop === 20 || checkDiv.offsetTop === 15);
		checkDiv.style.position = checkDiv.style.top = "";

		innerDiv.style.overflow = "hidden";
		innerDiv.style.position = "relative";

		this.subtractsBorderForOverflowNotVisible = (checkDiv.offsetTop === -5);

		this.doesNotIncludeMarginInBodyOffset = (body.offsetTop !== bodyMarginTop);

		body.removeChild( container );
		jQuery.offset.initialize = jQuery.noop;
	},

	bodyOffset: function( body ) {
		var top = body.offsetTop,
			left = body.offsetLeft;

		jQuery.offset.initialize();

		if ( jQuery.offset.doesNotIncludeMarginInBodyOffset ) {
			top  += parseFloat( jQuery.css(body, "marginTop") ) || 0;
			left += parseFloat( jQuery.css(body, "marginLeft") ) || 0;
		}

		return { top: top, left: left };
	},

	setOffset: function( elem, options, i ) {
		var position = jQuery.css( elem, "position" );

		// set position first, in-case top/left are set even on static elem
		if ( position === "static" ) {
			elem.style.position = "relative";
		}

		var curElem = jQuery( elem ),
			curOffset = curElem.offset(),
			curCSSTop = jQuery.css( elem, "top" ),
			curCSSLeft = jQuery.css( elem, "left" ),
			calculatePosition = (position === "absolute" || position === "fixed") && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1,
			props = {}, curPosition = {}, curTop, curLeft;

		// need to be able to calculate position if either top or left is auto and position is either absolute or fixed
		if ( calculatePosition ) {
			curPosition = curElem.position();
			curTop = curPosition.top;
			curLeft = curPosition.left;
		} else {
			curTop = parseFloat( curCSSTop ) || 0;
			curLeft = parseFloat( curCSSLeft ) || 0;
		}

		if ( jQuery.isFunction( options ) ) {
			options = options.call( elem, i, curOffset );
		}

		if (options.top != null) {
			props.top = (options.top - curOffset.top) + curTop;
		}
		if (options.left != null) {
			props.left = (options.left - curOffset.left) + curLeft;
		}

		if ( "using" in options ) {
			options.using.call( elem, props );
		} else {
			curElem.css( props );
		}
	}
};


jQuery.fn.extend({
	position: function() {
		if ( !this[0] ) {
			return null;
		}

		var elem = this[0],

		// Get *real* offsetParent
		offsetParent = this.offsetParent(),

		// Get correct offsets
		offset       = this.offset(),
		parentOffset = rroot.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset();

		// Subtract element margins
		// note: when an element has margin: auto the offsetLeft and marginLeft
		// are the same in Safari causing offset.left to incorrectly be 0
		offset.top  -= parseFloat( jQuery.css(elem, "marginTop") ) || 0;
		offset.left -= parseFloat( jQuery.css(elem, "marginLeft") ) || 0;

		// Add offsetParent borders
		parentOffset.top  += parseFloat( jQuery.css(offsetParent[0], "borderTopWidth") ) || 0;
		parentOffset.left += parseFloat( jQuery.css(offsetParent[0], "borderLeftWidth") ) || 0;

		// Subtract the two offsets
		return {
			top:  offset.top  - parentOffset.top,
			left: offset.left - parentOffset.left
		};
	},

	offsetParent: function() {
		return this.map(function() {
			var offsetParent = this.offsetParent || document.body;
			while ( offsetParent && (!rroot.test(offsetParent.nodeName) && jQuery.css(offsetParent, "position") === "static") ) {
				offsetParent = offsetParent.offsetParent;
			}
			return offsetParent;
		});
	}
});


// Create scrollLeft and scrollTop methods
jQuery.each( ["Left", "Top"], function( i, name ) {
	var method = "scroll" + name;

	jQuery.fn[ method ] = function( val ) {
		var elem, win;

		if ( val === undefined ) {
			elem = this[ 0 ];

			if ( !elem ) {
				return null;
			}

			win = getWindow( elem );

			// Return the scroll offset
			return win ? ("pageXOffset" in win) ? win[ i ? "pageYOffset" : "pageXOffset" ] :
				jQuery.support.boxModel && win.document.documentElement[ method ] ||
					win.document.body[ method ] :
				elem[ method ];
		}

		// Set the scroll offset
		return this.each(function() {
			win = getWindow( this );

			if ( win ) {
				win.scrollTo(
					!i ? val : jQuery( win ).scrollLeft(),
					 i ? val : jQuery( win ).scrollTop()
				);

			} else {
				this[ method ] = val;
			}
		});
	};
});

function getWindow( elem ) {
	return jQuery.isWindow( elem ) ?
		elem :
		elem.nodeType === 9 ?
			elem.defaultView || elem.parentWindow :
			false;
}




// Create width, height, innerHeight, innerWidth, outerHeight and outerWidth methods
jQuery.each([ "Height", "Width" ], function( i, name ) {

	var type = name.toLowerCase();

	// innerHeight and innerWidth
	jQuery.fn[ "inner" + name ] = function() {
		var elem = this[0];
		return elem && elem.style ?
			parseFloat( jQuery.css( elem, type, "padding" ) ) :
			null;
	};

	// outerHeight and outerWidth
	jQuery.fn[ "outer" + name ] = function( margin ) {
		var elem = this[0];
		return elem && elem.style ?
			parseFloat( jQuery.css( elem, type, margin ? "margin" : "border" ) ) :
			null;
	};

	jQuery.fn[ type ] = function( size ) {
		// Get window width or height
		var elem = this[0];
		if ( !elem ) {
			return size == null ? null : this;
		}

		if ( jQuery.isFunction( size ) ) {
			return this.each(function( i ) {
				var self = jQuery( this );
				self[ type ]( size.call( this, i, self[ type ]() ) );
			});
		}

		if ( jQuery.isWindow( elem ) ) {
			// Everyone else use document.documentElement or document.body depending on Quirks vs Standards mode
			// 3rd condition allows Nokia support, as it supports the docElem prop but not CSS1Compat
			var docElemProp = elem.document.documentElement[ "client" + name ];
			return elem.document.compatMode === "CSS1Compat" && docElemProp ||
				elem.document.body[ "client" + name ] || docElemProp;

		// Get document width or height
		} else if ( elem.nodeType === 9 ) {
			// Either scroll[Width/Height] or offset[Width/Height], whichever is greater
			return Math.max(
				elem.documentElement["client" + name],
				elem.body["scroll" + name], elem.documentElement["scroll" + name],
				elem.body["offset" + name], elem.documentElement["offset" + name]
			);

		// Get or set width or height on the element
		} else if ( size === undefined ) {
			var orig = jQuery.css( elem, type ),
				ret = parseFloat( orig );

			return jQuery.isNaN( ret ) ? orig : ret;

		// Set the width or height on the element (default to pixels if value is unitless)
		} else {
			return this.css( type, typeof size === "string" ? size : size + "px" );
		}
	};

});


// Expose jQuery to the global object
window.jQuery = window.$ = jQuery;
})(window);

/*!
 * jQuery UI 1.8.1
 *
 * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * http://docs.jquery.com/UI
 */
jQuery.ui||function(c){c.ui={version:"1.8.1",plugin:{add:function(a,b,d){a=c.ui[a].prototype;for(var e in d){a.plugins[e]=a.plugins[e]||[];a.plugins[e].push([b,d[e]])}},call:function(a,b,d){if((b=a.plugins[b])&&a.element[0].parentNode)for(var e=0;e<b.length;e++)a.options[b[e][0]]&&b[e][1].apply(a.element,d)}},contains:function(a,b){return document.compareDocumentPosition?a.compareDocumentPosition(b)&16:a!==b&&a.contains(b)},hasScroll:function(a,b){if(c(a).css("overflow")=="hidden")return false;
b=b&&b=="left"?"scrollLeft":"scrollTop";var d=false;if(a[b]>0)return true;a[b]=1;d=a[b]>0;a[b]=0;return d},isOverAxis:function(a,b,d){return a>b&&a<b+d},isOver:function(a,b,d,e,f,g){return c.ui.isOverAxis(a,d,f)&&c.ui.isOverAxis(b,e,g)},keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,
PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38}};c.fn.extend({_focus:c.fn.focus,focus:function(a,b){return typeof a==="number"?this.each(function(){var d=this;setTimeout(function(){c(d).focus();b&&b.call(d)},a)}):this._focus.apply(this,arguments)},enableSelection:function(){return this.attr("unselectable","off").css("MozUserSelect","")},disableSelection:function(){return this.attr("unselectable","on").css("MozUserSelect","none")},scrollParent:function(){var a;a=c.browser.msie&&/(static|relative)/.test(this.css("position"))||
/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(c.curCSS(this,"position",1))&&/(auto|scroll)/.test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0);return/fixed/.test(this.css("position"))||!a.length?c(document):a},zIndex:function(a){if(a!==
undefined)return this.css("zIndex",a);if(this.length){a=c(this[0]);for(var b;a.length&&a[0]!==document;){b=a.css("position");if(b=="absolute"||b=="relative"||b=="fixed"){b=parseInt(a.css("zIndex"));if(!isNaN(b)&&b!=0)return b}a=a.parent()}}return 0}});c.extend(c.expr[":"],{data:function(a,b,d){return!!c.data(a,d[3])},focusable:function(a){var b=a.nodeName.toLowerCase(),d=c.attr(a,"tabindex");return(/input|select|textarea|button|object/.test(b)?!a.disabled:"a"==b||"area"==b?a.href||!isNaN(d):!isNaN(d))&&
!c(a)["area"==b?"parents":"closest"](":hidden").length},tabbable:function(a){var b=c.attr(a,"tabindex");return(isNaN(b)||b>=0)&&c(a).is(":focusable")}})}(jQuery);
(function(b){var j=b.fn.remove;b.fn.remove=function(a,c){return this.each(function(){if(!c)if(!a||b.filter(a,[this]).length)b("*",this).add(this).each(function(){b(this).triggerHandler("remove")});return j.call(b(this),a,c)})};b.widget=function(a,c,d){var e=a.split(".")[0],f;a=a.split(".")[1];f=e+"-"+a;if(!d){d=c;c=b.Widget}b.expr[":"][f]=function(h){return!!b.data(h,a)};b[e]=b[e]||{};b[e][a]=function(h,g){arguments.length&&this._createWidget(h,g)};c=new c;c.options=b.extend({},c.options);b[e][a].prototype=
b.extend(true,c,{namespace:e,widgetName:a,widgetEventPrefix:b[e][a].prototype.widgetEventPrefix||a,widgetBaseClass:f},d);b.widget.bridge(a,b[e][a])};b.widget.bridge=function(a,c){b.fn[a]=function(d){var e=typeof d==="string",f=Array.prototype.slice.call(arguments,1),h=this;d=!e&&f.length?b.extend.apply(null,[true,d].concat(f)):d;if(e&&d.substring(0,1)==="_")return h;e?this.each(function(){var g=b.data(this,a),i=g&&b.isFunction(g[d])?g[d].apply(g,f):g;if(i!==g&&i!==undefined){h=i;return false}}):this.each(function(){var g=
b.data(this,a);if(g){d&&g.option(d);g._init()}else b.data(this,a,new c(d,this))});return h}};b.Widget=function(a,c){arguments.length&&this._createWidget(a,c)};b.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",options:{disabled:false},_createWidget:function(a,c){this.element=b(c).data(this.widgetName,this);this.options=b.extend(true,{},this.options,b.metadata&&b.metadata.get(c)[this.widgetName],a);var d=this;this.element.bind("remove."+this.widgetName,function(){d.destroy()});this._create();
this._init()},_create:function(){},_init:function(){},destroy:function(){this.element.unbind("."+this.widgetName).removeData(this.widgetName);this.widget().unbind("."+this.widgetName).removeAttr("aria-disabled").removeClass(this.widgetBaseClass+"-disabled ui-state-disabled")},widget:function(){return this.element},option:function(a,c){var d=a,e=this;if(arguments.length===0)return b.extend({},e.options);if(typeof a==="string"){if(c===undefined)return this.options[a];d={};d[a]=c}b.each(d,function(f,
h){e._setOption(f,h)});return e},_setOption:function(a,c){this.options[a]=c;if(a==="disabled")this.widget()[c?"addClass":"removeClass"](this.widgetBaseClass+"-disabled ui-state-disabled").attr("aria-disabled",c);return this},enable:function(){return this._setOption("disabled",false)},disable:function(){return this._setOption("disabled",true)},_trigger:function(a,c,d){var e=this.options[a];c=b.Event(c);c.type=(a===this.widgetEventPrefix?a:this.widgetEventPrefix+a).toLowerCase();d=d||{};if(c.originalEvent){a=
b.event.props.length;for(var f;a;){f=b.event.props[--a];c[f]=c.originalEvent[f]}}this.element.trigger(c,d);return!(b.isFunction(e)&&e.call(this.element[0],c,d)===false||c.isDefaultPrevented())}}})(jQuery);
(function(c){c.widget("ui.mouse",{options:{cancel:":input,option",distance:1,delay:0},_mouseInit:function(){var a=this;this.element.bind("mousedown."+this.widgetName,function(b){return a._mouseDown(b)}).bind("click."+this.widgetName,function(b){if(a._preventClickEvent){a._preventClickEvent=false;b.stopImmediatePropagation();return false}});this.started=false},_mouseDestroy:function(){this.element.unbind("."+this.widgetName)},_mouseDown:function(a){a.originalEvent=a.originalEvent||{};if(!a.originalEvent.mouseHandled){this._mouseStarted&&
this._mouseUp(a);this._mouseDownEvent=a;var b=this,e=a.which==1,f=typeof this.options.cancel=="string"?c(a.target).parents().add(a.target).filter(this.options.cancel).length:false;if(!e||f||!this._mouseCapture(a))return true;this.mouseDelayMet=!this.options.delay;if(!this.mouseDelayMet)this._mouseDelayTimer=setTimeout(function(){b.mouseDelayMet=true},this.options.delay);if(this._mouseDistanceMet(a)&&this._mouseDelayMet(a)){this._mouseStarted=this._mouseStart(a)!==false;if(!this._mouseStarted){a.preventDefault();
return true}}this._mouseMoveDelegate=function(d){return b._mouseMove(d)};this._mouseUpDelegate=function(d){return b._mouseUp(d)};c(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate);c.browser.safari||a.preventDefault();return a.originalEvent.mouseHandled=true}},_mouseMove:function(a){if(c.browser.msie&&!a.button)return this._mouseUp(a);if(this._mouseStarted){this._mouseDrag(a);return a.preventDefault()}if(this._mouseDistanceMet(a)&&
this._mouseDelayMet(a))(this._mouseStarted=this._mouseStart(this._mouseDownEvent,a)!==false)?this._mouseDrag(a):this._mouseUp(a);return!this._mouseStarted},_mouseUp:function(a){c(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted=false;this._preventClickEvent=a.target==this._mouseDownEvent.target;this._mouseStop(a)}return false},_mouseDistanceMet:function(a){return Math.max(Math.abs(this._mouseDownEvent.pageX-
a.pageX),Math.abs(this._mouseDownEvent.pageY-a.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return true}})})(jQuery);
(function(d){d.widget("ui.draggable",d.ui.mouse,{widgetEventPrefix:"drag",options:{addClasses:true,appendTo:"parent",axis:false,connectToSortable:false,containment:false,cursor:"auto",cursorAt:false,grid:false,handle:false,helper:"original",iframeFix:false,opacity:false,refreshPositions:false,revert:false,revertDuration:500,scope:"default",scroll:true,scrollSensitivity:20,scrollSpeed:20,snap:false,snapMode:"both",snapTolerance:20,stack:false,zIndex:false},_create:function(){if(this.options.helper==
"original"&&!/^(?:r|a|f)/.test(this.element.css("position")))this.element[0].style.position="relative";this.options.addClasses&&this.element.addClass("ui-draggable");this.options.disabled&&this.element.addClass("ui-draggable-disabled");this._mouseInit()},destroy:function(){if(this.element.data("draggable")){this.element.removeData("draggable").unbind(".draggable").removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled");this._mouseDestroy();return this}},_mouseCapture:function(a){var b=
this.options;if(this.helper||b.disabled||d(a.target).is(".ui-resizable-handle"))return false;this.handle=this._getHandle(a);if(!this.handle)return false;return true},_mouseStart:function(a){var b=this.options;this.helper=this._createHelper(a);this._cacheHelperProportions();if(d.ui.ddmanager)d.ui.ddmanager.current=this;this._cacheMargins();this.cssPosition=this.helper.css("position");this.scrollParent=this.helper.scrollParent();this.offset=this.positionAbs=this.element.offset();this.offset={top:this.offset.top-
this.margins.top,left:this.offset.left-this.margins.left};d.extend(this.offset,{click:{left:a.pageX-this.offset.left,top:a.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this.position=this._generatePosition(a);this.originalPageX=a.pageX;this.originalPageY=a.pageY;b.cursorAt&&this._adjustOffsetFromHelper(b.cursorAt);b.containment&&this._setContainment();if(this._trigger("start",a)===false){this._clear();return false}this._cacheHelperProportions();
d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,a);this.helper.addClass("ui-draggable-dragging");this._mouseDrag(a,true);return true},_mouseDrag:function(a,b){this.position=this._generatePosition(a);this.positionAbs=this._convertPositionTo("absolute");if(!b){b=this._uiHash();if(this._trigger("drag",a,b)===false){this._mouseUp({});return false}this.position=b.position}if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||
this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";d.ui.ddmanager&&d.ui.ddmanager.drag(this,a);return false},_mouseStop:function(a){var b=false;if(d.ui.ddmanager&&!this.options.dropBehaviour)b=d.ui.ddmanager.drop(this,a);if(this.dropped){b=this.dropped;this.dropped=false}if(!this.element[0]||!this.element[0].parentNode)return false;if(this.options.revert=="invalid"&&!b||this.options.revert=="valid"&&b||this.options.revert===true||d.isFunction(this.options.revert)&&this.options.revert.call(this.element,
b)){var c=this;d(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){c._trigger("stop",a)!==false&&c._clear()})}else this._trigger("stop",a)!==false&&this._clear();return false},cancel:function(){this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear();return this},_getHandle:function(a){var b=!this.options.handle||!d(this.options.handle,this.element).length?true:false;d(this.options.handle,this.element).find("*").andSelf().each(function(){if(this==
a.target)b=true});return b},_createHelper:function(a){var b=this.options;a=d.isFunction(b.helper)?d(b.helper.apply(this.element[0],[a])):b.helper=="clone"?this.element.clone():this.element;a.parents("body").length||a.appendTo(b.appendTo=="parent"?this.element[0].parentNode:b.appendTo);a[0]!=this.element[0]&&!/(fixed|absolute)/.test(a.css("position"))&&a.css("position","absolute");return a},_adjustOffsetFromHelper:function(a){if(typeof a=="string")a=a.split(" ");if(d.isArray(a))a={left:+a[0],top:+a[1]||
0};if("left"in a)this.offset.click.left=a.left+this.margins.left;if("right"in a)this.offset.click.left=this.helperProportions.width-a.right+this.margins.left;if("top"in a)this.offset.click.top=a.top+this.margins.top;if("bottom"in a)this.offset.click.top=this.helperProportions.height-a.bottom+this.margins.top},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var a=this.offsetParent.offset();if(this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],
this.offsetParent[0])){a.left+=this.scrollParent.scrollLeft();a.top+=this.scrollParent.scrollTop()}if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&d.browser.msie)a={top:0,left:0};return{top:a.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:a.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.element.position();return{top:a.top-
(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}else return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var a=this.options;if(a.containment==
"parent")a.containment=this.helper[0].parentNode;if(a.containment=="document"||a.containment=="window")this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,d(a.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(d(a.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(a.containment)&&
a.containment.constructor!=Array){var b=d(a.containment)[0];if(b){a=d(a.containment).offset();var c=d(b).css("overflow")!="hidden";this.containment=[a.left+(parseInt(d(b).css("borderLeftWidth"),10)||0)+(parseInt(d(b).css("paddingLeft"),10)||0)-this.margins.left,a.top+(parseInt(d(b).css("borderTopWidth"),10)||0)+(parseInt(d(b).css("paddingTop"),10)||0)-this.margins.top,a.left+(c?Math.max(b.scrollWidth,b.offsetWidth):b.offsetWidth)-(parseInt(d(b).css("borderLeftWidth"),10)||0)-(parseInt(d(b).css("paddingRight"),
10)||0)-this.helperProportions.width-this.margins.left,a.top+(c?Math.max(b.scrollHeight,b.offsetHeight):b.offsetHeight)-(parseInt(d(b).css("borderTopWidth"),10)||0)-(parseInt(d(b).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top]}}else if(a.containment.constructor==Array)this.containment=a.containment},_convertPositionTo:function(a,b){if(!b)b=this.position;a=a=="absolute"?1:-1;var c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],
this.offsetParent[0]))?this.offsetParent:this.scrollParent,f=/(html|body)/i.test(c[0].tagName);return{top:b.top+this.offset.relative.top*a+this.offset.parent.top*a-(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():f?0:c.scrollTop())*a),left:b.left+this.offset.relative.left*a+this.offset.parent.left*a-(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():
f?0:c.scrollLeft())*a)}},_generatePosition:function(a){var b=this.options,c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,f=/(html|body)/i.test(c[0].tagName),e=a.pageX,g=a.pageY;if(this.originalPosition){if(this.containment){if(a.pageX-this.offset.click.left<this.containment[0])e=this.containment[0]+this.offset.click.left;if(a.pageY-this.offset.click.top<this.containment[1])g=this.containment[1]+
this.offset.click.top;if(a.pageX-this.offset.click.left>this.containment[2])e=this.containment[2]+this.offset.click.left;if(a.pageY-this.offset.click.top>this.containment[3])g=this.containment[3]+this.offset.click.top}if(b.grid){g=this.originalPageY+Math.round((g-this.originalPageY)/b.grid[1])*b.grid[1];g=this.containment?!(g-this.offset.click.top<this.containment[1]||g-this.offset.click.top>this.containment[3])?g:!(g-this.offset.click.top<this.containment[1])?g-b.grid[1]:g+b.grid[1]:g;e=this.originalPageX+
Math.round((e-this.originalPageX)/b.grid[0])*b.grid[0];e=this.containment?!(e-this.offset.click.left<this.containment[0]||e-this.offset.click.left>this.containment[2])?e:!(e-this.offset.click.left<this.containment[0])?e-b.grid[0]:e+b.grid[0]:e}}return{top:g-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollTop():f?0:c.scrollTop()),left:e-this.offset.click.left-
this.offset.relative.left-this.offset.parent.left+(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():f?0:c.scrollLeft())}},_clear:function(){this.helper.removeClass("ui-draggable-dragging");this.helper[0]!=this.element[0]&&!this.cancelHelperRemoval&&this.helper.remove();this.helper=null;this.cancelHelperRemoval=false},_trigger:function(a,b,c){c=c||this._uiHash();d.ui.plugin.call(this,a,[b,c]);if(a=="drag")this.positionAbs=
this._convertPositionTo("absolute");return d.Widget.prototype._trigger.call(this,a,b,c)},plugins:{},_uiHash:function(){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}});d.extend(d.ui.draggable,{version:"1.8.1"});d.ui.plugin.add("draggable","connectToSortable",{start:function(a,b){var c=d(this).data("draggable"),f=c.options,e=d.extend({},b,{item:c.element});c.sortables=[];d(f.connectToSortable).each(function(){var g=d.data(this,"sortable");
if(g&&!g.options.disabled){c.sortables.push({instance:g,shouldRevert:g.options.revert});g._refreshItems();g._trigger("activate",a,e)}})},stop:function(a,b){var c=d(this).data("draggable"),f=d.extend({},b,{item:c.element});d.each(c.sortables,function(){if(this.instance.isOver){this.instance.isOver=0;c.cancelHelperRemoval=true;this.instance.cancelHelperRemoval=false;if(this.shouldRevert)this.instance.options.revert=true;this.instance._mouseStop(a);this.instance.options.helper=this.instance.options._helper;
c.options.helper=="original"&&this.instance.currentItem.css({top:"auto",left:"auto"})}else{this.instance.cancelHelperRemoval=false;this.instance._trigger("deactivate",a,f)}})},drag:function(a,b){var c=d(this).data("draggable"),f=this;d.each(c.sortables,function(){this.instance.positionAbs=c.positionAbs;this.instance.helperProportions=c.helperProportions;this.instance.offset.click=c.offset.click;if(this.instance._intersectsWith(this.instance.containerCache)){if(!this.instance.isOver){this.instance.isOver=
1;this.instance.currentItem=d(f).clone().appendTo(this.instance.element).data("sortable-item",true);this.instance.options._helper=this.instance.options.helper;this.instance.options.helper=function(){return b.helper[0]};a.target=this.instance.currentItem[0];this.instance._mouseCapture(a,true);this.instance._mouseStart(a,true,true);this.instance.offset.click.top=c.offset.click.top;this.instance.offset.click.left=c.offset.click.left;this.instance.offset.parent.left-=c.offset.parent.left-this.instance.offset.parent.left;
this.instance.offset.parent.top-=c.offset.parent.top-this.instance.offset.parent.top;c._trigger("toSortable",a);c.dropped=this.instance.element;c.currentItem=c.element;this.instance.fromOutside=c}this.instance.currentItem&&this.instance._mouseDrag(a)}else if(this.instance.isOver){this.instance.isOver=0;this.instance.cancelHelperRemoval=true;this.instance.options.revert=false;this.instance._trigger("out",a,this.instance._uiHash(this.instance));this.instance._mouseStop(a,true);this.instance.options.helper=
this.instance.options._helper;this.instance.currentItem.remove();this.instance.placeholder&&this.instance.placeholder.remove();c._trigger("fromSortable",a);c.dropped=false}})}});d.ui.plugin.add("draggable","cursor",{start:function(){var a=d("body"),b=d(this).data("draggable").options;if(a.css("cursor"))b._cursor=a.css("cursor");a.css("cursor",b.cursor)},stop:function(){var a=d(this).data("draggable").options;a._cursor&&d("body").css("cursor",a._cursor)}});d.ui.plugin.add("draggable","iframeFix",{start:function(){var a=
d(this).data("draggable").options;d(a.iframeFix===true?"iframe":a.iframeFix).each(function(){d('<div class="ui-draggable-iframeFix" style="background: #fff;"></div>').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1E3}).css(d(this).offset()).appendTo("body")})},stop:function(){d("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)})}});d.ui.plugin.add("draggable","opacity",{start:function(a,b){a=d(b.helper);b=d(this).data("draggable").options;
if(a.css("opacity"))b._opacity=a.css("opacity");a.css("opacity",b.opacity)},stop:function(a,b){a=d(this).data("draggable").options;a._opacity&&d(b.helper).css("opacity",a._opacity)}});d.ui.plugin.add("draggable","scroll",{start:function(){var a=d(this).data("draggable");if(a.scrollParent[0]!=document&&a.scrollParent[0].tagName!="HTML")a.overflowOffset=a.scrollParent.offset()},drag:function(a){var b=d(this).data("draggable"),c=b.options,f=false;if(b.scrollParent[0]!=document&&b.scrollParent[0].tagName!=
"HTML"){if(!c.axis||c.axis!="x")if(b.overflowOffset.top+b.scrollParent[0].offsetHeight-a.pageY<c.scrollSensitivity)b.scrollParent[0].scrollTop=f=b.scrollParent[0].scrollTop+c.scrollSpeed;else if(a.pageY-b.overflowOffset.top<c.scrollSensitivity)b.scrollParent[0].scrollTop=f=b.scrollParent[0].scrollTop-c.scrollSpeed;if(!c.axis||c.axis!="y")if(b.overflowOffset.left+b.scrollParent[0].offsetWidth-a.pageX<c.scrollSensitivity)b.scrollParent[0].scrollLeft=f=b.scrollParent[0].scrollLeft+c.scrollSpeed;else if(a.pageX-
b.overflowOffset.left<c.scrollSensitivity)b.scrollParent[0].scrollLeft=f=b.scrollParent[0].scrollLeft-c.scrollSpeed}else{if(!c.axis||c.axis!="x")if(a.pageY-d(document).scrollTop()<c.scrollSensitivity)f=d(document).scrollTop(d(document).scrollTop()-c.scrollSpeed);else if(d(window).height()-(a.pageY-d(document).scrollTop())<c.scrollSensitivity)f=d(document).scrollTop(d(document).scrollTop()+c.scrollSpeed);if(!c.axis||c.axis!="y")if(a.pageX-d(document).scrollLeft()<c.scrollSensitivity)f=d(document).scrollLeft(d(document).scrollLeft()-
c.scrollSpeed);else if(d(window).width()-(a.pageX-d(document).scrollLeft())<c.scrollSensitivity)f=d(document).scrollLeft(d(document).scrollLeft()+c.scrollSpeed)}f!==false&&d.ui.ddmanager&&!c.dropBehaviour&&d.ui.ddmanager.prepareOffsets(b,a)}});d.ui.plugin.add("draggable","snap",{start:function(){var a=d(this).data("draggable"),b=a.options;a.snapElements=[];d(b.snap.constructor!=String?b.snap.items||":data(draggable)":b.snap).each(function(){var c=d(this),f=c.offset();this!=a.element[0]&&a.snapElements.push({item:this,
width:c.outerWidth(),height:c.outerHeight(),top:f.top,left:f.left})})},drag:function(a,b){for(var c=d(this).data("draggable"),f=c.options,e=f.snapTolerance,g=b.offset.left,n=g+c.helperProportions.width,m=b.offset.top,o=m+c.helperProportions.height,h=c.snapElements.length-1;h>=0;h--){var i=c.snapElements[h].left,k=i+c.snapElements[h].width,j=c.snapElements[h].top,l=j+c.snapElements[h].height;if(i-e<g&&g<k+e&&j-e<m&&m<l+e||i-e<g&&g<k+e&&j-e<o&&o<l+e||i-e<n&&n<k+e&&j-e<m&&m<l+e||i-e<n&&n<k+e&&j-e<o&&
o<l+e){if(f.snapMode!="inner"){var p=Math.abs(j-o)<=e,q=Math.abs(l-m)<=e,r=Math.abs(i-n)<=e,s=Math.abs(k-g)<=e;if(p)b.position.top=c._convertPositionTo("relative",{top:j-c.helperProportions.height,left:0}).top-c.margins.top;if(q)b.position.top=c._convertPositionTo("relative",{top:l,left:0}).top-c.margins.top;if(r)b.position.left=c._convertPositionTo("relative",{top:0,left:i-c.helperProportions.width}).left-c.margins.left;if(s)b.position.left=c._convertPositionTo("relative",{top:0,left:k}).left-c.margins.left}var t=
p||q||r||s;if(f.snapMode!="outer"){p=Math.abs(j-m)<=e;q=Math.abs(l-o)<=e;r=Math.abs(i-g)<=e;s=Math.abs(k-n)<=e;if(p)b.position.top=c._convertPositionTo("relative",{top:j,left:0}).top-c.margins.top;if(q)b.position.top=c._convertPositionTo("relative",{top:l-c.helperProportions.height,left:0}).top-c.margins.top;if(r)b.position.left=c._convertPositionTo("relative",{top:0,left:i}).left-c.margins.left;if(s)b.position.left=c._convertPositionTo("relative",{top:0,left:k-c.helperProportions.width}).left-c.margins.left}if(!c.snapElements[h].snapping&&
(p||q||r||s||t))c.options.snap.snap&&c.options.snap.snap.call(c.element,a,d.extend(c._uiHash(),{snapItem:c.snapElements[h].item}));c.snapElements[h].snapping=p||q||r||s||t}else{c.snapElements[h].snapping&&c.options.snap.release&&c.options.snap.release.call(c.element,a,d.extend(c._uiHash(),{snapItem:c.snapElements[h].item}));c.snapElements[h].snapping=false}}}});d.ui.plugin.add("draggable","stack",{start:function(){var a=d(this).data("draggable").options;a=d.makeArray(d(a.stack)).sort(function(c,f){return(parseInt(d(c).css("zIndex"),
10)||0)-(parseInt(d(f).css("zIndex"),10)||0)});if(a.length){var b=parseInt(a[0].style.zIndex)||0;d(a).each(function(c){this.style.zIndex=b+c});this[0].style.zIndex=b+a.length}}});d.ui.plugin.add("draggable","zIndex",{start:function(a,b){a=d(b.helper);b=d(this).data("draggable").options;if(a.css("zIndex"))b._zIndex=a.css("zIndex");a.css("zIndex",b.zIndex)},stop:function(a,b){a=d(this).data("draggable").options;a._zIndex&&d(b.helper).css("zIndex",a._zIndex)}})})(jQuery);
(function(d){d.widget("ui.droppable",{widgetEventPrefix:"drop",options:{accept:"*",activeClass:false,addClasses:true,greedy:false,hoverClass:false,scope:"default",tolerance:"intersect"},_create:function(){var a=this.options,b=a.accept;this.isover=0;this.isout=1;this.accept=d.isFunction(b)?b:function(c){return c.is(b)};this.proportions={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight};d.ui.ddmanager.droppables[a.scope]=d.ui.ddmanager.droppables[a.scope]||[];d.ui.ddmanager.droppables[a.scope].push(this);
a.addClasses&&this.element.addClass("ui-droppable")},destroy:function(){for(var a=d.ui.ddmanager.droppables[this.options.scope],b=0;b<a.length;b++)a[b]==this&&a.splice(b,1);this.element.removeClass("ui-droppable ui-droppable-disabled").removeData("droppable").unbind(".droppable");return this},_setOption:function(a,b){if(a=="accept")this.accept=d.isFunction(b)?b:function(c){return c.is(b)};d.Widget.prototype._setOption.apply(this,arguments)},_activate:function(a){var b=d.ui.ddmanager.current;this.options.activeClass&&
this.element.addClass(this.options.activeClass);b&&this._trigger("activate",a,this.ui(b))},_deactivate:function(a){var b=d.ui.ddmanager.current;this.options.activeClass&&this.element.removeClass(this.options.activeClass);b&&this._trigger("deactivate",a,this.ui(b))},_over:function(a){var b=d.ui.ddmanager.current;if(!(!b||(b.currentItem||b.element)[0]==this.element[0]))if(this.accept.call(this.element[0],b.currentItem||b.element)){this.options.hoverClass&&this.element.addClass(this.options.hoverClass);
this._trigger("over",a,this.ui(b))}},_out:function(a){var b=d.ui.ddmanager.current;if(!(!b||(b.currentItem||b.element)[0]==this.element[0]))if(this.accept.call(this.element[0],b.currentItem||b.element)){this.options.hoverClass&&this.element.removeClass(this.options.hoverClass);this._trigger("out",a,this.ui(b))}},_drop:function(a,b){var c=b||d.ui.ddmanager.current;if(!c||(c.currentItem||c.element)[0]==this.element[0])return false;var e=false;this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function(){var g=
d.data(this,"droppable");if(g.options.greedy&&!g.options.disabled&&g.options.scope==c.options.scope&&g.accept.call(g.element[0],c.currentItem||c.element)&&d.ui.intersect(c,d.extend(g,{offset:g.element.offset()}),g.options.tolerance)){e=true;return false}});if(e)return false;if(this.accept.call(this.element[0],c.currentItem||c.element)){this.options.activeClass&&this.element.removeClass(this.options.activeClass);this.options.hoverClass&&this.element.removeClass(this.options.hoverClass);this._trigger("drop",
a,this.ui(c));return this.element}return false},ui:function(a){return{draggable:a.currentItem||a.element,helper:a.helper,position:a.position,offset:a.positionAbs}}});d.extend(d.ui.droppable,{version:"1.8.1"});d.ui.intersect=function(a,b,c){if(!b.offset)return false;var e=(a.positionAbs||a.position.absolute).left,g=e+a.helperProportions.width,f=(a.positionAbs||a.position.absolute).top,h=f+a.helperProportions.height,i=b.offset.left,k=i+b.proportions.width,j=b.offset.top,l=j+b.proportions.height;
switch(c){case "fit":return i<e&&g<k&&j<f&&h<l;case "intersect":return i<e+a.helperProportions.width/2&&g-a.helperProportions.width/2<k&&j<f+a.helperProportions.height/2&&h-a.helperProportions.height/2<l;case "pointer":return d.ui.isOver((a.positionAbs||a.position.absolute).top+(a.clickOffset||a.offset.click).top,(a.positionAbs||a.position.absolute).left+(a.clickOffset||a.offset.click).left,j,i,b.proportions.height,b.proportions.width);case "touch":return(f>=j&&f<=l||h>=j&&h<=l||f<j&&h>l)&&(e>=i&&
e<=k||g>=i&&g<=k||e<i&&g>k);default:return false}};d.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(a,b){var c=d.ui.ddmanager.droppables[a.options.scope]||[],e=b?b.type:null,g=(a.currentItem||a.element).find(":data(droppable)").andSelf(),f=0;a:for(;f<c.length;f++)if(!(c[f].options.disabled||a&&!c[f].accept.call(c[f].element[0],a.currentItem||a.element))){for(var h=0;h<g.length;h++)if(g[h]==c[f].element[0]){c[f].proportions.height=0;continue a}c[f].visible=c[f].element.css("display")!=
"none";if(c[f].visible){c[f].offset=c[f].element.offset();c[f].proportions={width:c[f].element[0].offsetWidth,height:c[f].element[0].offsetHeight};e=="mousedown"&&c[f]._activate.call(c[f],b)}}},drop:function(a,b){var c=false;d.each(d.ui.ddmanager.droppables[a.options.scope]||[],function(){if(this.options){if(!this.options.disabled&&this.visible&&d.ui.intersect(a,this,this.options.tolerance))c=c||this._drop.call(this,b);if(!this.options.disabled&&this.visible&&this.accept.call(this.element[0],a.currentItem||
a.element)){this.isout=1;this.isover=0;this._deactivate.call(this,b)}}});return c},drag:function(a,b){a.options.refreshPositions&&d.ui.ddmanager.prepareOffsets(a,b);d.each(d.ui.ddmanager.droppables[a.options.scope]||[],function(){if(!(this.options.disabled||this.greedyChild||!this.visible)){var c=d.ui.intersect(a,this,this.options.tolerance);if(c=!c&&this.isover==1?"isout":c&&this.isover==0?"isover":null){var e;if(this.options.greedy){var g=this.element.parents(":data(droppable):eq(0)");if(g.length){e=
d.data(g[0],"droppable");e.greedyChild=c=="isover"?1:0}}if(e&&c=="isover"){e.isover=0;e.isout=1;e._out.call(e,b)}this[c]=1;this[c=="isout"?"isover":"isout"]=0;this[c=="isover"?"_over":"_out"].call(this,b);if(e&&c=="isout"){e.isout=0;e.isover=1;e._over.call(e,b)}}}})}}})(jQuery);
(function(d){d.widget("ui.resizable",d.ui.mouse,{widgetEventPrefix:"resize",options:{alsoResize:false,animate:false,animateDuration:"slow",animateEasing:"swing",aspectRatio:false,autoHide:false,containment:false,ghost:false,grid:false,handles:"e,s,se",helper:false,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1E3},_create:function(){var b=this,a=this.options;this.element.addClass("ui-resizable");d.extend(this,{_aspectRatio:!!a.aspectRatio,aspectRatio:a.aspectRatio,originalElement:this.element,
_proportionallyResizeElements:[],_helper:a.helper||a.ghost||a.animate?a.helper||"ui-resizable-helper":null});if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)){/relative/.test(this.element.css("position"))&&d.browser.opera&&this.element.css({position:"relative",top:"auto",left:"auto"});this.element.wrap(d('<div class="ui-wrapper" style="overflow: hidden;"></div>').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),
top:this.element.css("top"),left:this.element.css("left")}));this.element=this.element.parent().data("resizable",this.element.data("resizable"));this.elementIsWrapper=true;this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")});this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0});this.originalResizeStyle=
this.originalElement.css("resize");this.originalElement.css("resize","none");this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"}));this.originalElement.css({margin:this.originalElement.css("margin")});this._proportionallyResize()}this.handles=a.handles||(!d(".ui-resizable-handle",this.element).length?"e,s,se":{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",
nw:".ui-resizable-nw"});if(this.handles.constructor==String){if(this.handles=="all")this.handles="n,e,s,w,se,sw,ne,nw";var c=this.handles.split(",");this.handles={};for(var e=0;e<c.length;e++){var g=d.trim(c[e]),f=d('<div class="ui-resizable-handle '+("ui-resizable-"+g)+'"></div>');/sw|se|ne|nw/.test(g)&&f.css({zIndex:++a.zIndex});"se"==g&&f.addClass("ui-icon ui-icon-gripsmall-diagonal-se");this.handles[g]=".ui-resizable-"+g;this.element.append(f)}}this._renderAxis=function(h){h=h||this.element;for(var i in this.handles){if(this.handles[i].constructor==
String)this.handles[i]=d(this.handles[i],this.element).show();if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var j=d(this.handles[i],this.element),l=0;l=/sw|ne|nw|se|n|s/.test(i)?j.outerHeight():j.outerWidth();j=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join("");h.css(j,l);this._proportionallyResize()}d(this.handles[i])}};this._renderAxis(this.element);this._handles=d(".ui-resizable-handle",this.element).disableSelection();
this._handles.mouseover(function(){if(!b.resizing){if(this.className)var h=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);b.axis=h&&h[1]?h[1]:"se"}});if(a.autoHide){this._handles.hide();d(this.element).addClass("ui-resizable-autohide").hover(function(){d(this).removeClass("ui-resizable-autohide");b._handles.show()},function(){if(!b.resizing){d(this).addClass("ui-resizable-autohide");b._handles.hide()}})}this._mouseInit()},destroy:function(){this._mouseDestroy();var b=function(c){d(c).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};
if(this.elementIsWrapper){b(this.element);var a=this.element;a.after(this.originalElement.css({position:a.css("position"),width:a.outerWidth(),height:a.outerHeight(),top:a.css("top"),left:a.css("left")})).remove()}this.originalElement.css("resize",this.originalResizeStyle);b(this.originalElement);return this},_mouseCapture:function(b){var a=false;for(var c in this.handles)if(d(this.handles[c])[0]==b.target)a=true;return!this.options.disabled&&a},_mouseStart:function(b){var a=this.options,c=this.element.position(),
e=this.element;this.resizing=true;this.documentScroll={top:d(document).scrollTop(),left:d(document).scrollLeft()};if(e.is(".ui-draggable")||/absolute/.test(e.css("position")))e.css({position:"absolute",top:c.top,left:c.left});d.browser.opera&&/relative/.test(e.css("position"))&&e.css({position:"relative",top:"auto",left:"auto"});this._renderProxy();c=m(this.helper.css("left"));var g=m(this.helper.css("top"));if(a.containment){c+=d(a.containment).scrollLeft()||0;g+=d(a.containment).scrollTop()||0}this.offset=
this.helper.offset();this.position={left:c,top:g};this.size=this._helper?{width:e.outerWidth(),height:e.outerHeight()}:{width:e.width(),height:e.height()};this.originalSize=this._helper?{width:e.outerWidth(),height:e.outerHeight()}:{width:e.width(),height:e.height()};this.originalPosition={left:c,top:g};this.sizeDiff={width:e.outerWidth()-e.width(),height:e.outerHeight()-e.height()};this.originalMousePosition={left:b.pageX,top:b.pageY};this.aspectRatio=typeof a.aspectRatio=="number"?a.aspectRatio:
this.originalSize.width/this.originalSize.height||1;a=d(".ui-resizable-"+this.axis).css("cursor");d("body").css("cursor",a=="auto"?this.axis+"-resize":a);e.addClass("ui-resizable-resizing");this._propagate("start",b);return true},_mouseDrag:function(b){var a=this.helper,c=this.originalMousePosition,e=this._change[this.axis];if(!e)return false;c=e.apply(this,[b,b.pageX-c.left||0,b.pageY-c.top||0]);if(this._aspectRatio||b.shiftKey)c=this._updateRatio(c,b);c=this._respectSize(c,b);this._propagate("resize",
b);a.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"});!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize();this._updateCache(c);this._trigger("resize",b,this.ui());return false},_mouseStop:function(b){this.resizing=false;var a=this.options,c=this;if(this._helper){var e=this._proportionallyResizeElements,g=e.length&&/textarea/i.test(e[0].nodeName);e=g&&d.ui.hasScroll(e[0],"left")?0:c.sizeDiff.height;
g={width:c.size.width-(g?0:c.sizeDiff.width),height:c.size.height-e};e=parseInt(c.element.css("left"),10)+(c.position.left-c.originalPosition.left)||null;var f=parseInt(c.element.css("top"),10)+(c.position.top-c.originalPosition.top)||null;a.animate||this.element.css(d.extend(g,{top:f,left:e}));c.helper.height(c.size.height);c.helper.width(c.size.width);this._helper&&!a.animate&&this._proportionallyResize()}d("body").css("cursor","auto");this.element.removeClass("ui-resizable-resizing");this._propagate("stop",
b);this._helper&&this.helper.remove();return false},_updateCache:function(b){this.offset=this.helper.offset();if(k(b.left))this.position.left=b.left;if(k(b.top))this.position.top=b.top;if(k(b.height))this.size.height=b.height;if(k(b.width))this.size.width=b.width},_updateRatio:function(b){var a=this.position,c=this.size,e=this.axis;if(b.height)b.width=c.height*this.aspectRatio;else if(b.width)b.height=c.width/this.aspectRatio;if(e=="sw"){b.left=a.left+(c.width-b.width);b.top=null}if(e=="nw"){b.top=
a.top+(c.height-b.height);b.left=a.left+(c.width-b.width)}return b},_respectSize:function(b){var a=this.options,c=this.axis,e=k(b.width)&&a.maxWidth&&a.maxWidth<b.width,g=k(b.height)&&a.maxHeight&&a.maxHeight<b.height,f=k(b.width)&&a.minWidth&&a.minWidth>b.width,h=k(b.height)&&a.minHeight&&a.minHeight>b.height;if(f)b.width=a.minWidth;if(h)b.height=a.minHeight;if(e)b.width=a.maxWidth;if(g)b.height=a.maxHeight;var i=this.originalPosition.left+this.originalSize.width,j=this.position.top+this.size.height,
l=/sw|nw|w/.test(c);c=/nw|ne|n/.test(c);if(f&&l)b.left=i-a.minWidth;if(e&&l)b.left=i-a.maxWidth;if(h&&c)b.top=j-a.minHeight;if(g&&c)b.top=j-a.maxHeight;if((a=!b.width&&!b.height)&&!b.left&&b.top)b.top=null;else if(a&&!b.top&&b.left)b.left=null;return b},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var b=this.helper||this.element,a=0;a<this._proportionallyResizeElements.length;a++){var c=this._proportionallyResizeElements[a];if(!this.borderDif){var e=[c.css("borderTopWidth"),
c.css("borderRightWidth"),c.css("borderBottomWidth"),c.css("borderLeftWidth")],g=[c.css("paddingTop"),c.css("paddingRight"),c.css("paddingBottom"),c.css("paddingLeft")];this.borderDif=d.map(e,function(f,h){f=parseInt(f,10)||0;h=parseInt(g[h],10)||0;return f+h})}d.browser.msie&&(d(b).is(":hidden")||d(b).parents(":hidden").length)||c.css({height:b.height()-this.borderDif[0]-this.borderDif[2]||0,width:b.width()-this.borderDif[1]-this.borderDif[3]||0})}},_renderProxy:function(){var b=this.options;this.elementOffset=
this.element.offset();if(this._helper){this.helper=this.helper||d('<div style="overflow:hidden;"></div>');var a=d.browser.msie&&d.browser.version<7,c=a?1:0;a=a?2:-1;this.helper.addClass(this._helper).css({width:this.element.outerWidth()+a,height:this.element.outerHeight()+a,position:"absolute",left:this.elementOffset.left-c+"px",top:this.elementOffset.top-c+"px",zIndex:++b.zIndex});this.helper.appendTo("body").disableSelection()}else this.helper=this.element},_change:{e:function(b,a){return{width:this.originalSize.width+
a}},w:function(b,a){return{left:this.originalPosition.left+a,width:this.originalSize.width-a}},n:function(b,a,c){return{top:this.originalPosition.top+c,height:this.originalSize.height-c}},s:function(b,a,c){return{height:this.originalSize.height+c}},se:function(b,a,c){return d.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[b,a,c]))},sw:function(b,a,c){return d.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[b,a,c]))},ne:function(b,a,c){return d.extend(this._change.n.apply(this,
arguments),this._change.e.apply(this,[b,a,c]))},nw:function(b,a,c){return d.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[b,a,c]))}},_propagate:function(b,a){d.ui.plugin.call(this,b,[a,this.ui()]);b!="resize"&&this._trigger(b,a,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}});d.extend(d.ui.resizable,
{version:"1.8.1"});d.ui.plugin.add("resizable","alsoResize",{start:function(){var b=d(this).data("resizable").options,a=function(c){d(c).each(function(){d(this).data("resizable-alsoresize",{width:parseInt(d(this).width(),10),height:parseInt(d(this).height(),10),left:parseInt(d(this).css("left"),10),top:parseInt(d(this).css("top"),10)})})};if(typeof b.alsoResize=="object"&&!b.alsoResize.parentNode)if(b.alsoResize.length){b.alsoResize=b.alsoResize[0];a(b.alsoResize)}else d.each(b.alsoResize,function(c){a(c)});
else a(b.alsoResize)},resize:function(){var b=d(this).data("resizable"),a=b.options,c=b.originalSize,e=b.originalPosition,g={height:b.size.height-c.height||0,width:b.size.width-c.width||0,top:b.position.top-e.top||0,left:b.position.left-e.left||0},f=function(h,i){d(h).each(function(){var j=d(this),l=d(this).data("resizable-alsoresize"),p={};d.each((i&&i.length?i:["width","height","top","left"])||["width","height","top","left"],function(n,o){if((n=(l[o]||0)+(g[o]||0))&&n>=0)p[o]=n||null});if(/relative/.test(j.css("position"))&&
d.browser.opera){b._revertToRelativePosition=true;j.css({position:"absolute",top:"auto",left:"auto"})}j.css(p)})};typeof a.alsoResize=="object"&&!a.alsoResize.nodeType?d.each(a.alsoResize,function(h,i){f(h,i)}):f(a.alsoResize)},stop:function(){var b=d(this).data("resizable");if(b._revertToRelativePosition&&d.browser.opera){b._revertToRelativePosition=false;el.css({position:"relative"})}d(this).removeData("resizable-alsoresize-start")}});d.ui.plugin.add("resizable","animate",{stop:function(b){var a=
d(this).data("resizable"),c=a.options,e=a._proportionallyResizeElements,g=e.length&&/textarea/i.test(e[0].nodeName),f=g&&d.ui.hasScroll(e[0],"left")?0:a.sizeDiff.height;g={width:a.size.width-(g?0:a.sizeDiff.width),height:a.size.height-f};f=parseInt(a.element.css("left"),10)+(a.position.left-a.originalPosition.left)||null;var h=parseInt(a.element.css("top"),10)+(a.position.top-a.originalPosition.top)||null;a.element.animate(d.extend(g,h&&f?{top:h,left:f}:{}),{duration:c.animateDuration,easing:c.animateEasing,
step:function(){var i={width:parseInt(a.element.css("width"),10),height:parseInt(a.element.css("height"),10),top:parseInt(a.element.css("top"),10),left:parseInt(a.element.css("left"),10)};e&&e.length&&d(e[0]).css({width:i.width,height:i.height});a._updateCache(i);a._propagate("resize",b)}})}});d.ui.plugin.add("resizable","containment",{start:function(){var b=d(this).data("resizable"),a=b.element,c=b.options.containment;if(a=c instanceof d?c.get(0):/parent/.test(c)?a.parent().get(0):c){b.containerElement=
d(a);if(/document/.test(c)||c==document){b.containerOffset={left:0,top:0};b.containerPosition={left:0,top:0};b.parentData={element:d(document),left:0,top:0,width:d(document).width(),height:d(document).height()||document.body.parentNode.scrollHeight}}else{var e=d(a),g=[];d(["Top","Right","Left","Bottom"]).each(function(i,j){g[i]=m(e.css("padding"+j))});b.containerOffset=e.offset();b.containerPosition=e.position();b.containerSize={height:e.innerHeight()-g[3],width:e.innerWidth()-g[1]};c=b.containerOffset;
var f=b.containerSize.height,h=b.containerSize.width;h=d.ui.hasScroll(a,"left")?a.scrollWidth:h;f=d.ui.hasScroll(a)?a.scrollHeight:f;b.parentData={element:a,left:c.left,top:c.top,width:h,height:f}}}},resize:function(b){var a=d(this).data("resizable"),c=a.options,e=a.containerOffset,g=a.position;b=a._aspectRatio||b.shiftKey;var f={top:0,left:0},h=a.containerElement;if(h[0]!=document&&/static/.test(h.css("position")))f=e;if(g.left<(a._helper?e.left:0)){a.size.width+=a._helper?a.position.left-e.left:
a.position.left-f.left;if(b)a.size.height=a.size.width/c.aspectRatio;a.position.left=c.helper?e.left:0}if(g.top<(a._helper?e.top:0)){a.size.height+=a._helper?a.position.top-e.top:a.position.top;if(b)a.size.width=a.size.height*c.aspectRatio;a.position.top=a._helper?e.top:0}a.offset.left=a.parentData.left+a.position.left;a.offset.top=a.parentData.top+a.position.top;c=Math.abs((a._helper?a.offset.left-f.left:a.offset.left-f.left)+a.sizeDiff.width);e=Math.abs((a._helper?a.offset.top-f.top:a.offset.top-
e.top)+a.sizeDiff.height);g=a.containerElement.get(0)==a.element.parent().get(0);f=/relative|absolute/.test(a.containerElement.css("position"));if(g&&f)c-=a.parentData.left;if(c+a.size.width>=a.parentData.width){a.size.width=a.parentData.width-c;if(b)a.size.height=a.size.width/a.aspectRatio}if(e+a.size.height>=a.parentData.height){a.size.height=a.parentData.height-e;if(b)a.size.width=a.size.height*a.aspectRatio}},stop:function(){var b=d(this).data("resizable"),a=b.options,c=b.containerOffset,e=b.containerPosition,
g=b.containerElement,f=d(b.helper),h=f.offset(),i=f.outerWidth()-b.sizeDiff.width;f=f.outerHeight()-b.sizeDiff.height;b._helper&&!a.animate&&/relative/.test(g.css("position"))&&d(this).css({left:h.left-e.left-c.left,width:i,height:f});b._helper&&!a.animate&&/static/.test(g.css("position"))&&d(this).css({left:h.left-e.left-c.left,width:i,height:f})}});d.ui.plugin.add("resizable","ghost",{start:function(){var b=d(this).data("resizable"),a=b.options,c=b.size;b.ghost=b.originalElement.clone();b.ghost.css({opacity:0.25,
display:"block",position:"relative",height:c.height,width:c.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof a.ghost=="string"?a.ghost:"");b.ghost.appendTo(b.helper)},resize:function(){var b=d(this).data("resizable");b.ghost&&b.ghost.css({position:"relative",height:b.size.height,width:b.size.width})},stop:function(){var b=d(this).data("resizable");b.ghost&&b.helper&&b.helper.get(0).removeChild(b.ghost.get(0))}});d.ui.plugin.add("resizable","grid",{resize:function(){var b=
d(this).data("resizable"),a=b.options,c=b.size,e=b.originalSize,g=b.originalPosition,f=b.axis;a.grid=typeof a.grid=="number"?[a.grid,a.grid]:a.grid;var h=Math.round((c.width-e.width)/(a.grid[0]||1))*(a.grid[0]||1);a=Math.round((c.height-e.height)/(a.grid[1]||1))*(a.grid[1]||1);if(/^(se|s|e)$/.test(f)){b.size.width=e.width+h;b.size.height=e.height+a}else if(/^(ne)$/.test(f)){b.size.width=e.width+h;b.size.height=e.height+a;b.position.top=g.top-a}else{if(/^(sw)$/.test(f)){b.size.width=e.width+h;b.size.height=
e.height+a}else{b.size.width=e.width+h;b.size.height=e.height+a;b.position.top=g.top-a}b.position.left=g.left-h}}});var m=function(b){return parseInt(b,10)||0},k=function(b){return!isNaN(parseInt(b,10))}})(jQuery);
(function(e){e.widget("ui.selectable",e.ui.mouse,{options:{appendTo:"body",autoRefresh:true,distance:0,filter:"*",tolerance:"touch"},_create:function(){var d=this;this.element.addClass("ui-selectable");this.dragged=false;var f;this.refresh=function(){f=e(d.options.filter,d.element[0]);f.each(function(){var c=e(this),b=c.offset();e.data(this,"selectable-item",{element:this,$element:c,left:b.left,top:b.top,right:b.left+c.outerWidth(),bottom:b.top+c.outerHeight(),startselected:false,selected:c.hasClass("ui-selected"),
selecting:c.hasClass("ui-selecting"),unselecting:c.hasClass("ui-unselecting")})})};this.refresh();this.selectees=f.addClass("ui-selectee");this._mouseInit();this.helper=e(document.createElement("div")).css({border:"1px dotted black"}).addClass("ui-selectable-helper")},destroy:function(){this.selectees.removeClass("ui-selectee").removeData("selectable-item");this.element.removeClass("ui-selectable ui-selectable-disabled").removeData("selectable").unbind(".selectable");this._mouseDestroy();return this},
_mouseStart:function(d){var f=this;this.opos=[d.pageX,d.pageY];if(!this.options.disabled){var c=this.options;this.selectees=e(c.filter,this.element[0]);this._trigger("start",d);e(c.appendTo).append(this.helper);this.helper.css({"z-index":100,position:"absolute",left:d.clientX,top:d.clientY,width:0,height:0});c.autoRefresh&&this.refresh();this.selectees.filter(".ui-selected").each(function(){var b=e.data(this,"selectable-item");b.startselected=true;if(!d.metaKey){b.$element.removeClass("ui-selected");
b.selected=false;b.$element.addClass("ui-unselecting");b.unselecting=true;f._trigger("unselecting",d,{unselecting:b.element})}});e(d.target).parents().andSelf().each(function(){var b=e.data(this,"selectable-item");if(b){b.$element.removeClass("ui-unselecting").addClass("ui-selecting");b.unselecting=false;b.selecting=true;b.selected=true;f._trigger("selecting",d,{selecting:b.element});return false}})}},_mouseDrag:function(d){var f=this;this.dragged=true;if(!this.options.disabled){var c=this.options,
b=this.opos[0],g=this.opos[1],h=d.pageX,i=d.pageY;if(b>h){var j=h;h=b;b=j}if(g>i){j=i;i=g;g=j}this.helper.css({left:b,top:g,width:h-b,height:i-g});this.selectees.each(function(){var a=e.data(this,"selectable-item");if(!(!a||a.element==f.element[0])){var k=false;if(c.tolerance=="touch")k=!(a.left>h||a.right<b||a.top>i||a.bottom<g);else if(c.tolerance=="fit")k=a.left>b&&a.right<h&&a.top>g&&a.bottom<i;if(k){if(a.selected){a.$element.removeClass("ui-selected");a.selected=false}if(a.unselecting){a.$element.removeClass("ui-unselecting");
a.unselecting=false}if(!a.selecting){a.$element.addClass("ui-selecting");a.selecting=true;f._trigger("selecting",d,{selecting:a.element})}}else{if(a.selecting)if(d.metaKey&&a.startselected){a.$element.removeClass("ui-selecting");a.selecting=false;a.$element.addClass("ui-selected");a.selected=true}else{a.$element.removeClass("ui-selecting");a.selecting=false;if(a.startselected){a.$element.addClass("ui-unselecting");a.unselecting=true}f._trigger("unselecting",d,{unselecting:a.element})}if(a.selected)if(!d.metaKey&&
!a.startselected){a.$element.removeClass("ui-selected");a.selected=false;a.$element.addClass("ui-unselecting");a.unselecting=true;f._trigger("unselecting",d,{unselecting:a.element})}}}});return false}},_mouseStop:function(d){var f=this;this.dragged=false;e(".ui-unselecting",this.element[0]).each(function(){var c=e.data(this,"selectable-item");c.$element.removeClass("ui-unselecting");c.unselecting=false;c.startselected=false;f._trigger("unselected",d,{unselected:c.element})});e(".ui-selecting",this.element[0]).each(function(){var c=
e.data(this,"selectable-item");c.$element.removeClass("ui-selecting").addClass("ui-selected");c.selecting=false;c.selected=true;c.startselected=true;f._trigger("selected",d,{selected:c.element})});this._trigger("stop",d);this.helper.remove();return false}});e.extend(e.ui.selectable,{version:"1.8.1"})})(jQuery);
(function(d){d.widget("ui.sortable",d.ui.mouse,{widgetEventPrefix:"sort",options:{appendTo:"parent",axis:false,connectWith:false,containment:false,cursor:"auto",cursorAt:false,dropOnEmpty:true,forcePlaceholderSize:false,forceHelperSize:false,grid:false,handle:false,helper:"original",items:"> *",opacity:false,placeholder:false,revert:false,scroll:true,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1E3},_create:function(){this.containerCache={};this.element.addClass("ui-sortable");
this.refresh();this.floating=this.items.length?/left|right/.test(this.items[0].item.css("float")):false;this.offset=this.element.offset();this._mouseInit()},destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled").removeData("sortable").unbind(".sortable");this._mouseDestroy();for(var a=this.items.length-1;a>=0;a--)this.items[a].item.removeData("sortable-item");return this},_setOption:function(a,b){if(a==="disabled"){this.options[a]=b;this.widget()[b?"addClass":"removeClass"]("ui-sortable-disabled")}else d.Widget.prototype._setOption.apply(self,
arguments)},_mouseCapture:function(a,b){if(this.reverting)return false;if(this.options.disabled||this.options.type=="static")return false;this._refreshItems(a);var c=null,e=this;d(a.target).parents().each(function(){if(d.data(this,"sortable-item")==e){c=d(this);return false}});if(d.data(a.target,"sortable-item")==e)c=d(a.target);if(!c)return false;if(this.options.handle&&!b){var f=false;d(this.options.handle,c).find("*").andSelf().each(function(){if(this==a.target)f=true});if(!f)return false}this.currentItem=
c;this._removeCurrentsFromItems();return true},_mouseStart:function(a,b,c){b=this.options;var e=this;this.currentContainer=this;this.refreshPositions();this.helper=this._createHelper(a);this._cacheHelperProportions();this._cacheMargins();this.scrollParent=this.helper.scrollParent();this.offset=this.currentItem.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};this.helper.css("position","absolute");this.cssPosition=this.helper.css("position");d.extend(this.offset,
{click:{left:a.pageX-this.offset.left,top:a.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this._generatePosition(a);this.originalPageX=a.pageX;this.originalPageY=a.pageY;b.cursorAt&&this._adjustOffsetFromHelper(b.cursorAt);this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]};this.helper[0]!=this.currentItem[0]&&this.currentItem.hide();this._createPlaceholder();b.containment&&this._setContainment();
if(b.cursor){if(d("body").css("cursor"))this._storedCursor=d("body").css("cursor");d("body").css("cursor",b.cursor)}if(b.opacity){if(this.helper.css("opacity"))this._storedOpacity=this.helper.css("opacity");this.helper.css("opacity",b.opacity)}if(b.zIndex){if(this.helper.css("zIndex"))this._storedZIndex=this.helper.css("zIndex");this.helper.css("zIndex",b.zIndex)}if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML")this.overflowOffset=this.scrollParent.offset();this._trigger("start",
a,this._uiHash());this._preserveHelperProportions||this._cacheHelperProportions();if(!c)for(c=this.containers.length-1;c>=0;c--)this.containers[c]._trigger("activate",a,e._uiHash(this));if(d.ui.ddmanager)d.ui.ddmanager.current=this;d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,a);this.dragging=true;this.helper.addClass("ui-sortable-helper");this._mouseDrag(a);return true},_mouseDrag:function(a){this.position=this._generatePosition(a);this.positionAbs=this._convertPositionTo("absolute");
if(!this.lastPositionAbs)this.lastPositionAbs=this.positionAbs;if(this.options.scroll){var b=this.options,c=false;if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"){if(this.overflowOffset.top+this.scrollParent[0].offsetHeight-a.pageY<b.scrollSensitivity)this.scrollParent[0].scrollTop=c=this.scrollParent[0].scrollTop+b.scrollSpeed;else if(a.pageY-this.overflowOffset.top<b.scrollSensitivity)this.scrollParent[0].scrollTop=c=this.scrollParent[0].scrollTop-b.scrollSpeed;if(this.overflowOffset.left+
this.scrollParent[0].offsetWidth-a.pageX<b.scrollSensitivity)this.scrollParent[0].scrollLeft=c=this.scrollParent[0].scrollLeft+b.scrollSpeed;else if(a.pageX-this.overflowOffset.left<b.scrollSensitivity)this.scrollParent[0].scrollLeft=c=this.scrollParent[0].scrollLeft-b.scrollSpeed}else{if(a.pageY-d(document).scrollTop()<b.scrollSensitivity)c=d(document).scrollTop(d(document).scrollTop()-b.scrollSpeed);else if(d(window).height()-(a.pageY-d(document).scrollTop())<b.scrollSensitivity)c=d(document).scrollTop(d(document).scrollTop()+
b.scrollSpeed);if(a.pageX-d(document).scrollLeft()<b.scrollSensitivity)c=d(document).scrollLeft(d(document).scrollLeft()-b.scrollSpeed);else if(d(window).width()-(a.pageX-d(document).scrollLeft())<b.scrollSensitivity)c=d(document).scrollLeft(d(document).scrollLeft()+b.scrollSpeed)}c!==false&&d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,a)}this.positionAbs=this._convertPositionTo("absolute");if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+
"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";for(b=this.items.length-1;b>=0;b--){c=this.items[b];var e=c.item[0],f=this._intersectsWithPointer(c);if(f)if(e!=this.currentItem[0]&&this.placeholder[f==1?"next":"prev"]()[0]!=e&&!d.ui.contains(this.placeholder[0],e)&&(this.options.type=="semi-dynamic"?!d.ui.contains(this.element[0],e):true)){this.direction=f==1?"down":"up";if(this.options.tolerance=="pointer"||this._intersectsWithSides(c))this._rearrange(a,
c);else break;this._trigger("change",a,this._uiHash());break}}this._contactContainers(a);d.ui.ddmanager&&d.ui.ddmanager.drag(this,a);this._trigger("sort",a,this._uiHash());this.lastPositionAbs=this.positionAbs;return false},_mouseStop:function(a,b){if(a){d.ui.ddmanager&&!this.options.dropBehaviour&&d.ui.ddmanager.drop(this,a);if(this.options.revert){var c=this;b=c.placeholder.offset();c.reverting=true;d(this.helper).animate({left:b.left-this.offset.parent.left-c.margins.left+(this.offsetParent[0]==
document.body?0:this.offsetParent[0].scrollLeft),top:b.top-this.offset.parent.top-c.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},parseInt(this.options.revert,10)||500,function(){c._clear(a)})}else this._clear(a,b);return false}},cancel:function(){var a=this;if(this.dragging){this._mouseUp();this.options.helper=="original"?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):this.currentItem.show();for(var b=this.containers.length-1;b>=0;b--){this.containers[b]._trigger("deactivate",
null,a._uiHash(this));if(this.containers[b].containerCache.over){this.containers[b]._trigger("out",null,a._uiHash(this));this.containers[b].containerCache.over=0}}}this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]);this.options.helper!="original"&&this.helper&&this.helper[0].parentNode&&this.helper.remove();d.extend(this,{helper:null,dragging:false,reverting:false,_noFinalSort:null});this.domPosition.prev?d(this.domPosition.prev).after(this.currentItem):
d(this.domPosition.parent).prepend(this.currentItem);return this},serialize:function(a){var b=this._getItemsAsjQuery(a&&a.connected),c=[];a=a||{};d(b).each(function(){var e=(d(a.item||this).attr(a.attribute||"id")||"").match(a.expression||/(.+)[-=_](.+)/);if(e)c.push((a.key||e[1]+"[]")+"="+(a.key&&a.expression?e[1]:e[2]))});return c.join("&")},toArray:function(a){var b=this._getItemsAsjQuery(a&&a.connected),c=[];a=a||{};b.each(function(){c.push(d(a.item||this).attr(a.attribute||"id")||"")});return c},
_intersectsWith:function(a){var b=this.positionAbs.left,c=b+this.helperProportions.width,e=this.positionAbs.top,f=e+this.helperProportions.height,g=a.left,h=g+a.width,i=a.top,k=i+a.height,j=this.offset.click.top,l=this.offset.click.left;j=e+j>i&&e+j<k&&b+l>g&&b+l<h;return this.options.tolerance=="pointer"||this.options.forcePointerForContainers||this.options.tolerance!="pointer"&&this.helperProportions[this.floating?"width":"height"]>a[this.floating?"width":"height"]?j:g<b+this.helperProportions.width/
2&&c-this.helperProportions.width/2<h&&i<e+this.helperProportions.height/2&&f-this.helperProportions.height/2<k},_intersectsWithPointer:function(a){var b=d.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,a.top,a.height);a=d.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,a.left,a.width);b=b&&a;a=this._getDragVerticalDirection();var c=this._getDragHorizontalDirection();if(!b)return false;return this.floating?c&&c=="right"||a=="down"?2:1:a&&(a=="down"?2:1)},_intersectsWithSides:function(a){var b=
d.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,a.top+a.height/2,a.height);a=d.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,a.left+a.width/2,a.width);var c=this._getDragVerticalDirection(),e=this._getDragHorizontalDirection();return this.floating&&e?e=="right"&&a||e=="left"&&!a:c&&(c=="down"&&b||c=="up"&&!b)},_getDragVerticalDirection:function(){var a=this.positionAbs.top-this.lastPositionAbs.top;return a!=0&&(a>0?"down":"up")},_getDragHorizontalDirection:function(){var a=
this.positionAbs.left-this.lastPositionAbs.left;return a!=0&&(a>0?"right":"left")},refresh:function(a){this._refreshItems(a);this.refreshPositions();return this},_connectWith:function(){var a=this.options;return a.connectWith.constructor==String?[a.connectWith]:a.connectWith},_getItemsAsjQuery:function(a){var b=[],c=[],e=this._connectWith();if(e&&a)for(a=e.length-1;a>=0;a--)for(var f=d(e[a]),g=f.length-1;g>=0;g--){var h=d.data(f[g],"sortable");if(h&&h!=this&&!h.options.disabled)c.push([d.isFunction(h.options.items)?
h.options.items.call(h.element):d(h.options.items,h.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),h])}c.push([d.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):d(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]);for(a=c.length-1;a>=0;a--)c[a][0].each(function(){b.push(this)});return d(b)},_removeCurrentsFromItems:function(){for(var a=this.currentItem.find(":data(sortable-item)"),
b=0;b<this.items.length;b++)for(var c=0;c<a.length;c++)a[c]==this.items[b].item[0]&&this.items.splice(b,1)},_refreshItems:function(a){this.items=[];this.containers=[this];var b=this.items,c=[[d.isFunction(this.options.items)?this.options.items.call(this.element[0],a,{item:this.currentItem}):d(this.options.items,this.element),this]],e=this._connectWith();if(e)for(var f=e.length-1;f>=0;f--)for(var g=d(e[f]),h=g.length-1;h>=0;h--){var i=d.data(g[h],"sortable");if(i&&i!=this&&!i.options.disabled){c.push([d.isFunction(i.options.items)?
i.options.items.call(i.element[0],a,{item:this.currentItem}):d(i.options.items,i.element),i]);this.containers.push(i)}}for(f=c.length-1;f>=0;f--){a=c[f][1];e=c[f][0];h=0;for(g=e.length;h<g;h++){i=d(e[h]);i.data("sortable-item",a);b.push({item:i,instance:a,width:0,height:0,left:0,top:0})}}},refreshPositions:function(a){if(this.offsetParent&&this.helper)this.offset.parent=this._getParentOffset();for(var b=this.items.length-1;b>=0;b--){var c=this.items[b],e=this.options.toleranceElement?d(this.options.toleranceElement,
c.item):c.item;if(!a){c.width=e.outerWidth();c.height=e.outerHeight()}e=e.offset();c.left=e.left;c.top=e.top}if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(b=this.containers.length-1;b>=0;b--){e=this.containers[b].element.offset();this.containers[b].containerCache.left=e.left;this.containers[b].containerCache.top=e.top;this.containers[b].containerCache.width=this.containers[b].element.outerWidth();this.containers[b].containerCache.height=
this.containers[b].element.outerHeight()}return this},_createPlaceholder:function(a){var b=a||this,c=b.options;if(!c.placeholder||c.placeholder.constructor==String){var e=c.placeholder;c.placeholder={element:function(){var f=d(document.createElement(b.currentItem[0].nodeName)).addClass(e||b.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper")[0];if(!e)f.style.visibility="hidden";return f},update:function(f,g){if(!(e&&!c.forcePlaceholderSize)){g.height()||g.height(b.currentItem.innerHeight()-
parseInt(b.currentItem.css("paddingTop")||0,10)-parseInt(b.currentItem.css("paddingBottom")||0,10));g.width()||g.width(b.currentItem.innerWidth()-parseInt(b.currentItem.css("paddingLeft")||0,10)-parseInt(b.currentItem.css("paddingRight")||0,10))}}}}b.placeholder=d(c.placeholder.element.call(b.element,b.currentItem));b.currentItem.after(b.placeholder);c.placeholder.update(b,b.placeholder)},_contactContainers:function(a){for(var b=null,c=null,e=this.containers.length-1;e>=0;e--)if(!d.ui.contains(this.currentItem[0],
this.containers[e].element[0]))if(this._intersectsWith(this.containers[e].containerCache)){if(!(b&&d.ui.contains(this.containers[e].element[0],b.element[0]))){b=this.containers[e];c=e}}else if(this.containers[e].containerCache.over){this.containers[e]._trigger("out",a,this._uiHash(this));this.containers[e].containerCache.over=0}if(b)if(this.containers.length===1){this.containers[c]._trigger("over",a,this._uiHash(this));this.containers[c].containerCache.over=1}else if(this.currentContainer!=this.containers[c]){b=
1E4;e=null;for(var f=this.positionAbs[this.containers[c].floating?"left":"top"],g=this.items.length-1;g>=0;g--)if(d.ui.contains(this.containers[c].element[0],this.items[g].item[0])){var h=this.items[g][this.containers[c].floating?"left":"top"];if(Math.abs(h-f)<b){b=Math.abs(h-f);e=this.items[g]}}if(e||this.options.dropOnEmpty){this.currentContainer=this.containers[c];e?this._rearrange(a,e,null,true):this._rearrange(a,null,this.containers[c].element,true);this._trigger("change",a,this._uiHash());this.containers[c]._trigger("change",
a,this._uiHash(this));this.options.placeholder.update(this.currentContainer,this.placeholder);this.containers[c]._trigger("over",a,this._uiHash(this));this.containers[c].containerCache.over=1}}},_createHelper:function(a){var b=this.options;a=d.isFunction(b.helper)?d(b.helper.apply(this.element[0],[a,this.currentItem])):b.helper=="clone"?this.currentItem.clone():this.currentItem;a.parents("body").length||d(b.appendTo!="parent"?b.appendTo:this.currentItem[0].parentNode)[0].appendChild(a[0]);if(a[0]==
this.currentItem[0])this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")};if(a[0].style.width==""||b.forceHelperSize)a.width(this.currentItem.width());if(a[0].style.height==""||b.forceHelperSize)a.height(this.currentItem.height());return a},_adjustOffsetFromHelper:function(a){if(typeof a=="string")a=a.split(" ");if(d.isArray(a))a={left:+a[0],top:+a[1]||
0};if("left"in a)this.offset.click.left=a.left+this.margins.left;if("right"in a)this.offset.click.left=this.helperProportions.width-a.right+this.margins.left;if("top"in a)this.offset.click.top=a.top+this.margins.top;if("bottom"in a)this.offset.click.top=this.helperProportions.height-a.bottom+this.margins.top},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var a=this.offsetParent.offset();if(this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],
this.offsetParent[0])){a.left+=this.scrollParent.scrollLeft();a.top+=this.scrollParent.scrollTop()}if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&d.browser.msie)a={top:0,left:0};return{top:a.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:a.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.currentItem.position();return{top:a.top-
(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}else return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.currentItem.css("marginLeft"),10)||0,top:parseInt(this.currentItem.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var a=this.options;
if(a.containment=="parent")a.containment=this.helper[0].parentNode;if(a.containment=="document"||a.containment=="window")this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,d(a.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(d(a.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(a.containment)){var b=
d(a.containment)[0];a=d(a.containment).offset();var c=d(b).css("overflow")!="hidden";this.containment=[a.left+(parseInt(d(b).css("borderLeftWidth"),10)||0)+(parseInt(d(b).css("paddingLeft"),10)||0)-this.margins.left,a.top+(parseInt(d(b).css("borderTopWidth"),10)||0)+(parseInt(d(b).css("paddingTop"),10)||0)-this.margins.top,a.left+(c?Math.max(b.scrollWidth,b.offsetWidth):b.offsetWidth)-(parseInt(d(b).css("borderLeftWidth"),10)||0)-(parseInt(d(b).css("paddingRight"),10)||0)-this.helperProportions.width-
this.margins.left,a.top+(c?Math.max(b.scrollHeight,b.offsetHeight):b.offsetHeight)-(parseInt(d(b).css("borderTopWidth"),10)||0)-(parseInt(d(b).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top]}},_convertPositionTo:function(a,b){if(!b)b=this.position;a=a=="absolute"?1:-1;var c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(c[0].tagName);return{top:b.top+
this.offset.relative.top*a+this.offset.parent.top*a-(d.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():e?0:c.scrollTop())*a),left:b.left+this.offset.relative.left*a+this.offset.parent.left*a-(d.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():e?0:c.scrollLeft())*a)}},_generatePosition:function(a){var b=this.options,c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],
this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(c[0].tagName);if(this.cssPosition=="relative"&&!(this.scrollParent[0]!=document&&this.scrollParent[0]!=this.offsetParent[0]))this.offset.relative=this._getRelativeOffset();var f=a.pageX,g=a.pageY;if(this.originalPosition){if(this.containment){if(a.pageX-this.offset.click.left<this.containment[0])f=this.containment[0]+this.offset.click.left;if(a.pageY-this.offset.click.top<this.containment[1])g=this.containment[1]+this.offset.click.top;
if(a.pageX-this.offset.click.left>this.containment[2])f=this.containment[2]+this.offset.click.left;if(a.pageY-this.offset.click.top>this.containment[3])g=this.containment[3]+this.offset.click.top}if(b.grid){g=this.originalPageY+Math.round((g-this.originalPageY)/b.grid[1])*b.grid[1];g=this.containment?!(g-this.offset.click.top<this.containment[1]||g-this.offset.click.top>this.containment[3])?g:!(g-this.offset.click.top<this.containment[1])?g-b.grid[1]:g+b.grid[1]:g;f=this.originalPageX+Math.round((f-
this.originalPageX)/b.grid[0])*b.grid[0];f=this.containment?!(f-this.offset.click.left<this.containment[0]||f-this.offset.click.left>this.containment[2])?f:!(f-this.offset.click.left<this.containment[0])?f-b.grid[0]:f+b.grid[0]:f}}return{top:g-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(d.browser.safari&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollTop():e?0:c.scrollTop()),left:f-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+
(d.browser.safari&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():e?0:c.scrollLeft())}},_rearrange:function(a,b,c,e){c?c[0].appendChild(this.placeholder[0]):b.item[0].parentNode.insertBefore(this.placeholder[0],this.direction=="down"?b.item[0]:b.item[0].nextSibling);this.counter=this.counter?++this.counter:1;var f=this,g=this.counter;window.setTimeout(function(){g==f.counter&&f.refreshPositions(!e)},0)},_clear:function(a,b){this.reverting=false;var c=[];!this._noFinalSort&&
this.currentItem[0].parentNode&&this.placeholder.before(this.currentItem);this._noFinalSort=null;if(this.helper[0]==this.currentItem[0]){for(var e in this._storedCSS)if(this._storedCSS[e]=="auto"||this._storedCSS[e]=="static")this._storedCSS[e]="";this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else this.currentItem.show();this.fromOutside&&!b&&c.push(function(f){this._trigger("receive",f,this._uiHash(this.fromOutside))});if((this.fromOutside||this.domPosition.prev!=this.currentItem.prev().not(".ui-sortable-helper")[0]||
this.domPosition.parent!=this.currentItem.parent()[0])&&!b)c.push(function(f){this._trigger("update",f,this._uiHash())});if(!d.ui.contains(this.element[0],this.currentItem[0])){b||c.push(function(f){this._trigger("remove",f,this._uiHash())});for(e=this.containers.length-1;e>=0;e--)if(d.ui.contains(this.containers[e].element[0],this.currentItem[0])&&!b){c.push(function(f){return function(g){f._trigger("receive",g,this._uiHash(this))}}.call(this,this.containers[e]));c.push(function(f){return function(g){f._trigger("update",
g,this._uiHash(this))}}.call(this,this.containers[e]))}}for(e=this.containers.length-1;e>=0;e--){b||c.push(function(f){return function(g){f._trigger("deactivate",g,this._uiHash(this))}}.call(this,this.containers[e]));if(this.containers[e].containerCache.over){c.push(function(f){return function(g){f._trigger("out",g,this._uiHash(this))}}.call(this,this.containers[e]));this.containers[e].containerCache.over=0}}this._storedCursor&&d("body").css("cursor",this._storedCursor);this._storedOpacity&&this.helper.css("opacity",
this._storedOpacity);if(this._storedZIndex)this.helper.css("zIndex",this._storedZIndex=="auto"?"":this._storedZIndex);this.dragging=false;if(this.cancelHelperRemoval){if(!b){this._trigger("beforeStop",a,this._uiHash());for(e=0;e<c.length;e++)c[e].call(this,a);this._trigger("stop",a,this._uiHash())}return false}b||this._trigger("beforeStop",a,this._uiHash());this.placeholder[0].parentNode.removeChild(this.placeholder[0]);this.helper[0]!=this.currentItem[0]&&this.helper.remove();this.helper=null;if(!b){for(e=
0;e<c.length;e++)c[e].call(this,a);this._trigger("stop",a,this._uiHash())}this.fromOutside=false;return true},_trigger:function(){d.Widget.prototype._trigger.apply(this,arguments)===false&&this.cancel()},_uiHash:function(a){var b=a||this;return{helper:b.helper,placeholder:b.placeholder||d([]),position:b.position,originalPosition:b.originalPosition,offset:b.positionAbs,item:b.currentItem,sender:a?a.element:null}}});d.extend(d.ui.sortable,{version:"1.8.1"})})(jQuery);
jQuery.effects||function(f){function k(c){var a;if(c&&c.constructor==Array&&c.length==3)return c;if(a=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(c))return[parseInt(a[1],10),parseInt(a[2],10),parseInt(a[3],10)];if(a=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(c))return[parseFloat(a[1])*2.55,parseFloat(a[2])*2.55,parseFloat(a[3])*2.55];if(a=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(c))return[parseInt(a[1],
16),parseInt(a[2],16),parseInt(a[3],16)];if(a=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(c))return[parseInt(a[1]+a[1],16),parseInt(a[2]+a[2],16),parseInt(a[3]+a[3],16)];if(/rgba\(0, 0, 0, 0\)/.exec(c))return l.transparent;return l[f.trim(c).toLowerCase()]}function q(c,a){var b;do{b=f.curCSS(c,a);if(b!=""&&b!="transparent"||f.nodeName(c,"body"))break;a="backgroundColor"}while(c=c.parentNode);return k(b)}function m(){var c=document.defaultView?document.defaultView.getComputedStyle(this,null):this.currentStyle,
a={},b,d;if(c&&c.length&&c[0]&&c[c[0]])for(var e=c.length;e--;){b=c[e];if(typeof c[b]=="string"){d=b.replace(/\-(\w)/g,function(g,h){return h.toUpperCase()});a[d]=c[b]}}else for(b in c)if(typeof c[b]==="string")a[b]=c[b];return a}function n(c){var a,b;for(a in c){b=c[a];if(b==null||f.isFunction(b)||a in r||/scrollbar/.test(a)||!/color/i.test(a)&&isNaN(parseFloat(b)))delete c[a]}return c}function s(c,a){var b={_:0},d;for(d in a)if(c[d]!=a[d])b[d]=a[d];return b}function j(c,a,b,d){if(typeof c=="object"){d=
a;b=null;a=c;c=a.effect}if(f.isFunction(a)){d=a;b=null;a={}}if(f.isFunction(b)){d=b;b=null}if(typeof a=="number"||f.fx.speeds[a]){d=b;b=a;a={}}a=a||{};b=b||a.duration;b=f.fx.off?0:typeof b=="number"?b:f.fx.speeds[b]||f.fx.speeds._default;d=d||a.complete;return[c,a,b,d]}f.effects={};f.each(["backgroundColor","borderBottomColor","borderLeftColor","borderRightColor","borderTopColor","color","outlineColor"],function(c,a){f.fx.step[a]=function(b){if(!b.colorInit){b.start=q(b.elem,a);b.end=k(b.end);b.colorInit=
true}b.elem.style[a]="rgb("+Math.max(Math.min(parseInt(b.pos*(b.end[0]-b.start[0])+b.start[0],10),255),0)+","+Math.max(Math.min(parseInt(b.pos*(b.end[1]-b.start[1])+b.start[1],10),255),0)+","+Math.max(Math.min(parseInt(b.pos*(b.end[2]-b.start[2])+b.start[2],10),255),0)+")"}});var l={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,
183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,
165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0],transparent:[255,255,255]},o=["add","remove","toggle"],r={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};f.effects.animateClass=function(c,a,b,d){if(f.isFunction(b)){d=b;b=null}return this.each(function(){var e=f(this),g=e.attr("style")||" ",h=n(m.call(this)),p,t=e.attr("className");f.each(o,function(u,
i){c[i]&&e[i+"Class"](c[i])});p=n(m.call(this));e.attr("className",t);e.animate(s(h,p),a,b,function(){f.each(o,function(u,i){c[i]&&e[i+"Class"](c[i])});if(typeof e.attr("style")=="object"){e.attr("style").cssText="";e.attr("style").cssText=g}else e.attr("style",g);d&&d.apply(this,arguments)})})};f.fn.extend({_addClass:f.fn.addClass,addClass:function(c,a,b,d){return a?f.effects.animateClass.apply(this,[{add:c},a,b,d]):this._addClass(c)},_removeClass:f.fn.removeClass,removeClass:function(c,a,b,d){return a?
f.effects.animateClass.apply(this,[{remove:c},a,b,d]):this._removeClass(c)},_toggleClass:f.fn.toggleClass,toggleClass:function(c,a,b,d,e){return typeof a=="boolean"||a===undefined?b?f.effects.animateClass.apply(this,[a?{add:c}:{remove:c},b,d,e]):this._toggleClass(c,a):f.effects.animateClass.apply(this,[{toggle:c},a,b,d])},switchClass:function(c,a,b,d,e){return f.effects.animateClass.apply(this,[{add:a,remove:c},b,d,e])}});f.extend(f.effects,{version:"1.8.1",save:function(c,a){for(var b=0;b<a.length;b++)a[b]!==
null&&c.data("ec.storage."+a[b],c[0].style[a[b]])},restore:function(c,a){for(var b=0;b<a.length;b++)a[b]!==null&&c.css(a[b],c.data("ec.storage."+a[b]))},setMode:function(c,a){if(a=="toggle")a=c.is(":hidden")?"show":"hide";return a},getBaseline:function(c,a){var b;switch(c[0]){case "top":b=0;break;case "middle":b=0.5;break;case "bottom":b=1;break;default:b=c[0]/a.height}switch(c[1]){case "left":c=0;break;case "center":c=0.5;break;case "right":c=1;break;default:c=c[1]/a.width}return{x:c,y:b}},createWrapper:function(c){if(c.parent().is(".ui-effects-wrapper"))return c.parent();
var a={width:c.outerWidth(true),height:c.outerHeight(true),"float":c.css("float")},b=f("<div></div>").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0});c.wrap(b);b=c.parent();if(c.css("position")=="static"){b.css({position:"relative"});c.css({position:"relative"})}else{f.extend(a,{position:c.css("position"),zIndex:c.css("z-index")});f.each(["top","left","bottom","right"],function(d,e){a[e]=c.css(e);if(isNaN(parseInt(a[e],10)))a[e]="auto"});
c.css({position:"relative",top:0,left:0})}return b.css(a).show()},removeWrapper:function(c){if(c.parent().is(".ui-effects-wrapper"))return c.parent().replaceWith(c);return c},setTransition:function(c,a,b,d){d=d||{};f.each(a,function(e,g){unit=c.cssUnit(g);if(unit[0]>0)d[g]=unit[0]*b+unit[1]});return d}});f.fn.extend({effect:function(c){var a=j.apply(this,arguments);a={options:a[1],duration:a[2],callback:a[3]};var b=f.effects[c];return b&&!f.fx.off?b.call(this,a):this},_show:f.fn.show,show:function(c){if(!c||
typeof c=="number"||f.fx.speeds[c])return this._show.apply(this,arguments);else{var a=j.apply(this,arguments);a[1].mode="show";return this.effect.apply(this,a)}},_hide:f.fn.hide,hide:function(c){if(!c||typeof c=="number"||f.fx.speeds[c])return this._hide.apply(this,arguments);else{var a=j.apply(this,arguments);a[1].mode="hide";return this.effect.apply(this,a)}},__toggle:f.fn.toggle,toggle:function(c){if(!c||typeof c=="number"||f.fx.speeds[c]||typeof c=="boolean"||f.isFunction(c))return this.__toggle.apply(this,
arguments);else{var a=j.apply(this,arguments);a[1].mode="toggle";return this.effect.apply(this,a)}},cssUnit:function(c){var a=this.css(c),b=[];f.each(["em","px","%","pt"],function(d,e){if(a.indexOf(e)>0)b=[parseFloat(a),e]});return b}});f.easing.jswing=f.easing.swing;f.extend(f.easing,{def:"easeOutQuad",swing:function(c,a,b,d,e){return f.easing[f.easing.def](c,a,b,d,e)},easeInQuad:function(c,a,b,d,e){return d*(a/=e)*a+b},easeOutQuad:function(c,a,b,d,e){return-d*(a/=e)*(a-2)+b},easeInOutQuad:function(c,
a,b,d,e){if((a/=e/2)<1)return d/2*a*a+b;return-d/2*(--a*(a-2)-1)+b},easeInCubic:function(c,a,b,d,e){return d*(a/=e)*a*a+b},easeOutCubic:function(c,a,b,d,e){return d*((a=a/e-1)*a*a+1)+b},easeInOutCubic:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a+b;return d/2*((a-=2)*a*a+2)+b},easeInQuart:function(c,a,b,d,e){return d*(a/=e)*a*a*a+b},easeOutQuart:function(c,a,b,d,e){return-d*((a=a/e-1)*a*a*a-1)+b},easeInOutQuart:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a*a+b;return-d/2*((a-=2)*a*a*a-2)+
b},easeInQuint:function(c,a,b,d,e){return d*(a/=e)*a*a*a*a+b},easeOutQuint:function(c,a,b,d,e){return d*((a=a/e-1)*a*a*a*a+1)+b},easeInOutQuint:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a*a*a+b;return d/2*((a-=2)*a*a*a*a+2)+b},easeInSine:function(c,a,b,d,e){return-d*Math.cos(a/e*(Math.PI/2))+d+b},easeOutSine:function(c,a,b,d,e){return d*Math.sin(a/e*(Math.PI/2))+b},easeInOutSine:function(c,a,b,d,e){return-d/2*(Math.cos(Math.PI*a/e)-1)+b},easeInExpo:function(c,a,b,d,e){return a==0?b:d*Math.pow(2,
10*(a/e-1))+b},easeOutExpo:function(c,a,b,d,e){return a==e?b+d:d*(-Math.pow(2,-10*a/e)+1)+b},easeInOutExpo:function(c,a,b,d,e){if(a==0)return b;if(a==e)return b+d;if((a/=e/2)<1)return d/2*Math.pow(2,10*(a-1))+b;return d/2*(-Math.pow(2,-10*--a)+2)+b},easeInCirc:function(c,a,b,d,e){return-d*(Math.sqrt(1-(a/=e)*a)-1)+b},easeOutCirc:function(c,a,b,d,e){return d*Math.sqrt(1-(a=a/e-1)*a)+b},easeInOutCirc:function(c,a,b,d,e){if((a/=e/2)<1)return-d/2*(Math.sqrt(1-a*a)-1)+b;return d/2*(Math.sqrt(1-(a-=2)*
a)+1)+b},easeInElastic:function(c,a,b,d,e){c=1.70158;var g=0,h=d;if(a==0)return b;if((a/=e)==1)return b+d;g||(g=e*0.3);if(h<Math.abs(d)){h=d;c=g/4}else c=g/(2*Math.PI)*Math.asin(d/h);return-(h*Math.pow(2,10*(a-=1))*Math.sin((a*e-c)*2*Math.PI/g))+b},easeOutElastic:function(c,a,b,d,e){c=1.70158;var g=0,h=d;if(a==0)return b;if((a/=e)==1)return b+d;g||(g=e*0.3);if(h<Math.abs(d)){h=d;c=g/4}else c=g/(2*Math.PI)*Math.asin(d/h);return h*Math.pow(2,-10*a)*Math.sin((a*e-c)*2*Math.PI/g)+d+b},easeInOutElastic:function(c,
a,b,d,e){c=1.70158;var g=0,h=d;if(a==0)return b;if((a/=e/2)==2)return b+d;g||(g=e*0.3*1.5);if(h<Math.abs(d)){h=d;c=g/4}else c=g/(2*Math.PI)*Math.asin(d/h);if(a<1)return-0.5*h*Math.pow(2,10*(a-=1))*Math.sin((a*e-c)*2*Math.PI/g)+b;return h*Math.pow(2,-10*(a-=1))*Math.sin((a*e-c)*2*Math.PI/g)*0.5+d+b},easeInBack:function(c,a,b,d,e,g){if(g==undefined)g=1.70158;return d*(a/=e)*a*((g+1)*a-g)+b},easeOutBack:function(c,a,b,d,e,g){if(g==undefined)g=1.70158;return d*((a=a/e-1)*a*((g+1)*a+g)+1)+b},easeInOutBack:function(c,
a,b,d,e,g){if(g==undefined)g=1.70158;if((a/=e/2)<1)return d/2*a*a*(((g*=1.525)+1)*a-g)+b;return d/2*((a-=2)*a*(((g*=1.525)+1)*a+g)+2)+b},easeInBounce:function(c,a,b,d,e){return d-f.easing.easeOutBounce(c,e-a,0,d,e)+b},easeOutBounce:function(c,a,b,d,e){return(a/=e)<1/2.75?d*7.5625*a*a+b:a<2/2.75?d*(7.5625*(a-=1.5/2.75)*a+0.75)+b:a<2.5/2.75?d*(7.5625*(a-=2.25/2.75)*a+0.9375)+b:d*(7.5625*(a-=2.625/2.75)*a+0.984375)+b},easeInOutBounce:function(c,a,b,d,e){if(a<e/2)return f.easing.easeInBounce(c,a*2,0,
d,e)*0.5+b;return f.easing.easeOutBounce(c,a*2-e,0,d,e)*0.5+d*0.5+b}})}(jQuery);
(function(b){b.effects.blind=function(c){return this.queue(function(){var a=b(this),g=["position","top","left"],f=b.effects.setMode(a,c.options.mode||"hide"),d=c.options.direction||"vertical";b.effects.save(a,g);a.show();var e=b.effects.createWrapper(a).css({overflow:"hidden"}),h=d=="vertical"?"height":"width";d=d=="vertical"?e.height():e.width();f=="show"&&e.css(h,0);var i={};i[h]=f=="show"?d:0;e.animate(i,c.duration,c.options.easing,function(){f=="hide"&&a.hide();b.effects.restore(a,g);b.effects.removeWrapper(a);
c.callback&&c.callback.apply(a[0],arguments);a.dequeue()})})}})(jQuery);
(function(e){e.effects.bounce=function(b){return this.queue(function(){var a=e(this),l=["position","top","left"],h=e.effects.setMode(a,b.options.mode||"effect"),d=b.options.direction||"up",c=b.options.distance||20,m=b.options.times||5,i=b.duration||250;/show|hide/.test(h)&&l.push("opacity");e.effects.save(a,l);a.show();e.effects.createWrapper(a);var f=d=="up"||d=="down"?"top":"left";d=d=="up"||d=="left"?"pos":"neg";c=b.options.distance||(f=="top"?a.outerHeight({margin:true})/3:a.outerWidth({margin:true})/
3);if(h=="show")a.css("opacity",0).css(f,d=="pos"?-c:c);if(h=="hide")c/=m*2;h!="hide"&&m--;if(h=="show"){var g={opacity:1};g[f]=(d=="pos"?"+=":"-=")+c;a.animate(g,i/2,b.options.easing);c/=2;m--}for(g=0;g<m;g++){var j={},k={};j[f]=(d=="pos"?"-=":"+=")+c;k[f]=(d=="pos"?"+=":"-=")+c;a.animate(j,i/2,b.options.easing).animate(k,i/2,b.options.easing);c=h=="hide"?c*2:c/2}if(h=="hide"){g={opacity:0};g[f]=(d=="pos"?"-=":"+=")+c;a.animate(g,i/2,b.options.easing,function(){a.hide();e.effects.restore(a,l);e.effects.removeWrapper(a);
b.callback&&b.callback.apply(this,arguments)})}else{j={};k={};j[f]=(d=="pos"?"-=":"+=")+c;k[f]=(d=="pos"?"+=":"-=")+c;a.animate(j,i/2,b.options.easing).animate(k,i/2,b.options.easing,function(){e.effects.restore(a,l);e.effects.removeWrapper(a);b.callback&&b.callback.apply(this,arguments)})}a.queue("fx",function(){a.dequeue()});a.dequeue()})}})(jQuery);
(function(b){b.effects.clip=function(e){return this.queue(function(){var a=b(this),i=["position","top","left","height","width"],f=b.effects.setMode(a,e.options.mode||"hide"),c=e.options.direction||"vertical";b.effects.save(a,i);a.show();var d=b.effects.createWrapper(a).css({overflow:"hidden"});d=a[0].tagName=="IMG"?d:a;var g={size:c=="vertical"?"height":"width",position:c=="vertical"?"top":"left"};c=c=="vertical"?d.height():d.width();if(f=="show"){d.css(g.size,0);d.css(g.position,c/2)}var h={};h[g.size]=
f=="show"?c:0;h[g.position]=f=="show"?0:c/2;d.animate(h,{queue:false,duration:e.duration,easing:e.options.easing,complete:function(){f=="hide"&&a.hide();b.effects.restore(a,i);b.effects.removeWrapper(a);e.callback&&e.callback.apply(a[0],arguments);a.dequeue()}})})}})(jQuery);
(function(c){c.effects.drop=function(d){return this.queue(function(){var a=c(this),h=["position","top","left","opacity"],e=c.effects.setMode(a,d.options.mode||"hide"),b=d.options.direction||"left";c.effects.save(a,h);a.show();c.effects.createWrapper(a);var f=b=="up"||b=="down"?"top":"left";b=b=="up"||b=="left"?"pos":"neg";var g=d.options.distance||(f=="top"?a.outerHeight({margin:true})/2:a.outerWidth({margin:true})/2);if(e=="show")a.css("opacity",0).css(f,b=="pos"?-g:g);var i={opacity:e=="show"?1:
0};i[f]=(e=="show"?b=="pos"?"+=":"-=":b=="pos"?"-=":"+=")+g;a.animate(i,{queue:false,duration:d.duration,easing:d.options.easing,complete:function(){e=="hide"&&a.hide();c.effects.restore(a,h);c.effects.removeWrapper(a);d.callback&&d.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery);
(function(j){j.effects.explode=function(a){return this.queue(function(){var c=a.options.pieces?Math.round(Math.sqrt(a.options.pieces)):3,d=a.options.pieces?Math.round(Math.sqrt(a.options.pieces)):3;a.options.mode=a.options.mode=="toggle"?j(this).is(":visible")?"hide":"show":a.options.mode;var b=j(this).show().css("visibility","hidden"),g=b.offset();g.top-=parseInt(b.css("marginTop"),10)||0;g.left-=parseInt(b.css("marginLeft"),10)||0;for(var h=b.outerWidth(true),i=b.outerHeight(true),e=0;e<c;e++)for(var f=
0;f<d;f++)b.clone().appendTo("body").wrap("<div></div>").css({position:"absolute",visibility:"visible",left:-f*(h/d),top:-e*(i/c)}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:h/d,height:i/c,left:g.left+f*(h/d)+(a.options.mode=="show"?(f-Math.floor(d/2))*(h/d):0),top:g.top+e*(i/c)+(a.options.mode=="show"?(e-Math.floor(c/2))*(i/c):0),opacity:a.options.mode=="show"?0:1}).animate({left:g.left+f*(h/d)+(a.options.mode=="show"?0:(f-Math.floor(d/2))*(h/d)),top:g.top+
e*(i/c)+(a.options.mode=="show"?0:(e-Math.floor(c/2))*(i/c)),opacity:a.options.mode=="show"?1:0},a.duration||500);setTimeout(function(){a.options.mode=="show"?b.css({visibility:"visible"}):b.css({visibility:"visible"}).hide();a.callback&&a.callback.apply(b[0]);b.dequeue();j("div.ui-effects-explode").remove()},a.duration||500)})}})(jQuery);
(function(b){b.effects.fade=function(a){return this.queue(function(){var c=b(this),d=b.effects.setMode(c,a.options.mode||"hide");c.animate({opacity:d},{queue:false,duration:a.duration,easing:a.options.easing,complete:function(){a.callback&&a.callback.apply(this,arguments);c.dequeue()}})})}})(jQuery);
(function(c){c.effects.fold=function(a){return this.queue(function(){var b=c(this),j=["position","top","left"],d=c.effects.setMode(b,a.options.mode||"hide"),g=a.options.size||15,h=!!a.options.horizFirst,k=a.duration?a.duration/2:c.fx.speeds._default/2;c.effects.save(b,j);b.show();var e=c.effects.createWrapper(b).css({overflow:"hidden"}),f=d=="show"!=h,l=f?["width","height"]:["height","width"];f=f?[e.width(),e.height()]:[e.height(),e.width()];var i=/([0-9]+)%/.exec(g);if(i)g=parseInt(i[1],10)/100*
f[d=="hide"?0:1];if(d=="show")e.css(h?{height:0,width:g}:{height:g,width:0});h={};i={};h[l[0]]=d=="show"?f[0]:g;i[l[1]]=d=="show"?f[1]:0;e.animate(h,k,a.options.easing).animate(i,k,a.options.easing,function(){d=="hide"&&b.hide();c.effects.restore(b,j);c.effects.removeWrapper(b);a.callback&&a.callback.apply(b[0],arguments);b.dequeue()})})}})(jQuery);
(function(b){b.effects.highlight=function(c){return this.queue(function(){var a=b(this),e=["backgroundImage","backgroundColor","opacity"],d=b.effects.setMode(a,c.options.mode||"show"),f={backgroundColor:a.css("backgroundColor")};if(d=="hide")f.opacity=0;b.effects.save(a,e);a.show().css({backgroundImage:"none",backgroundColor:c.options.color||"#ffff99"}).animate(f,{queue:false,duration:c.duration,easing:c.options.easing,complete:function(){d=="hide"&&a.hide();b.effects.restore(a,e);d=="show"&&!b.support.opacity&&
this.style.removeAttribute("filter");c.callback&&c.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery);
(function(d){d.effects.pulsate=function(a){return this.queue(function(){var b=d(this),c=d.effects.setMode(b,a.options.mode||"show");times=(a.options.times||5)*2-1;duration=a.duration?a.duration/2:d.fx.speeds._default/2;isVisible=b.is(":visible");animateTo=0;if(!isVisible){b.css("opacity",0).show();animateTo=1}if(c=="hide"&&isVisible||c=="show"&&!isVisible)times--;for(c=0;c<times;c++){b.animate({opacity:animateTo},duration,a.options.easing);animateTo=(animateTo+1)%2}b.animate({opacity:animateTo},duration,
a.options.easing,function(){animateTo==0&&b.hide();a.callback&&a.callback.apply(this,arguments)});b.queue("fx",function(){b.dequeue()}).dequeue()})}})(jQuery);
(function(c){c.effects.puff=function(b){return this.queue(function(){var a=c(this),e=c.effects.setMode(a,b.options.mode||"hide"),g=parseInt(b.options.percent,10)||150,h=g/100,i={height:a.height(),width:a.width()};c.extend(b.options,{fade:true,mode:e,percent:e=="hide"?g:100,from:e=="hide"?i:{height:i.height*h,width:i.width*h}});a.effect("scale",b.options,b.duration,b.callback);a.dequeue()})};c.effects.scale=function(b){return this.queue(function(){var a=c(this),e=c.extend(true,{},b.options),g=c.effects.setMode(a,
b.options.mode||"effect"),h=parseInt(b.options.percent,10)||(parseInt(b.options.percent,10)==0?0:g=="hide"?0:100),i=b.options.direction||"both",f=b.options.origin;if(g!="effect"){e.origin=f||["middle","center"];e.restore=true}f={height:a.height(),width:a.width()};a.from=b.options.from||(g=="show"?{height:0,width:0}:f);h={y:i!="horizontal"?h/100:1,x:i!="vertical"?h/100:1};a.to={height:f.height*h.y,width:f.width*h.x};if(b.options.fade){if(g=="show"){a.from.opacity=0;a.to.opacity=1}if(g=="hide"){a.from.opacity=
1;a.to.opacity=0}}e.from=a.from;e.to=a.to;e.mode=g;a.effect("size",e,b.duration,b.callback);a.dequeue()})};c.effects.size=function(b){return this.queue(function(){var a=c(this),e=["position","top","left","width","height","overflow","opacity"],g=["position","top","left","overflow","opacity"],h=["width","height","overflow"],i=["fontSize"],f=["borderTopWidth","borderBottomWidth","paddingTop","paddingBottom"],k=["borderLeftWidth","borderRightWidth","paddingLeft","paddingRight"],p=c.effects.setMode(a,
b.options.mode||"effect"),n=b.options.restore||false,m=b.options.scale||"both",l=b.options.origin,j={height:a.height(),width:a.width()};a.from=b.options.from||j;a.to=b.options.to||j;if(l){l=c.effects.getBaseline(l,j);a.from.top=(j.height-a.from.height)*l.y;a.from.left=(j.width-a.from.width)*l.x;a.to.top=(j.height-a.to.height)*l.y;a.to.left=(j.width-a.to.width)*l.x}var d={from:{y:a.from.height/j.height,x:a.from.width/j.width},to:{y:a.to.height/j.height,x:a.to.width/j.width}};if(m=="box"||m=="both"){if(d.from.y!=
d.to.y){e=e.concat(f);a.from=c.effects.setTransition(a,f,d.from.y,a.from);a.to=c.effects.setTransition(a,f,d.to.y,a.to)}if(d.from.x!=d.to.x){e=e.concat(k);a.from=c.effects.setTransition(a,k,d.from.x,a.from);a.to=c.effects.setTransition(a,k,d.to.x,a.to)}}if(m=="content"||m=="both")if(d.from.y!=d.to.y){e=e.concat(i);a.from=c.effects.setTransition(a,i,d.from.y,a.from);a.to=c.effects.setTransition(a,i,d.to.y,a.to)}c.effects.save(a,n?e:g);a.show();c.effects.createWrapper(a);a.css("overflow","hidden").css(a.from);
if(m=="content"||m=="both"){f=f.concat(["marginTop","marginBottom"]).concat(i);k=k.concat(["marginLeft","marginRight"]);h=e.concat(f).concat(k);a.find("*[width]").each(function(){child=c(this);n&&c.effects.save(child,h);var o={height:child.height(),width:child.width()};child.from={height:o.height*d.from.y,width:o.width*d.from.x};child.to={height:o.height*d.to.y,width:o.width*d.to.x};if(d.from.y!=d.to.y){child.from=c.effects.setTransition(child,f,d.from.y,child.from);child.to=c.effects.setTransition(child,
f,d.to.y,child.to)}if(d.from.x!=d.to.x){child.from=c.effects.setTransition(child,k,d.from.x,child.from);child.to=c.effects.setTransition(child,k,d.to.x,child.to)}child.css(child.from);child.animate(child.to,b.duration,b.options.easing,function(){n&&c.effects.restore(child,h)})})}a.animate(a.to,{queue:false,duration:b.duration,easing:b.options.easing,complete:function(){a.to.opacity===0&&a.css("opacity",a.from.opacity);p=="hide"&&a.hide();c.effects.restore(a,n?e:g);c.effects.removeWrapper(a);b.callback&&
b.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery);
(function(d){d.effects.shake=function(a){return this.queue(function(){var b=d(this),j=["position","top","left"];d.effects.setMode(b,a.options.mode||"effect");var c=a.options.direction||"left",e=a.options.distance||20,l=a.options.times||3,f=a.duration||a.options.duration||140;d.effects.save(b,j);b.show();d.effects.createWrapper(b);var g=c=="up"||c=="down"?"top":"left",h=c=="up"||c=="left"?"pos":"neg";c={};var i={},k={};c[g]=(h=="pos"?"-=":"+=")+e;i[g]=(h=="pos"?"+=":"-=")+e*2;k[g]=(h=="pos"?"-=":"+=")+
e*2;b.animate(c,f,a.options.easing);for(e=1;e<l;e++)b.animate(i,f,a.options.easing).animate(k,f,a.options.easing);b.animate(i,f,a.options.easing).animate(c,f/2,a.options.easing,function(){d.effects.restore(b,j);d.effects.removeWrapper(b);a.callback&&a.callback.apply(this,arguments)});b.queue("fx",function(){b.dequeue()});b.dequeue()})}})(jQuery);
(function(c){c.effects.slide=function(d){return this.queue(function(){var a=c(this),h=["position","top","left"],e=c.effects.setMode(a,d.options.mode||"show"),b=d.options.direction||"left";c.effects.save(a,h);a.show();c.effects.createWrapper(a).css({overflow:"hidden"});var f=b=="up"||b=="down"?"top":"left";b=b=="up"||b=="left"?"pos":"neg";var g=d.options.distance||(f=="top"?a.outerHeight({margin:true}):a.outerWidth({margin:true}));if(e=="show")a.css(f,b=="pos"?-g:g);var i={};i[f]=(e=="show"?b=="pos"?
"+=":"-=":b=="pos"?"-=":"+=")+g;a.animate(i,{queue:false,duration:d.duration,easing:d.options.easing,complete:function(){e=="hide"&&a.hide();c.effects.restore(a,h);c.effects.removeWrapper(a);d.callback&&d.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery);
(function(e){e.effects.transfer=function(a){return this.queue(function(){var b=e(this),c=e(a.options.to),d=c.offset();c={top:d.top,left:d.left,height:c.innerHeight(),width:c.innerWidth()};d=b.offset();var f=e('<div class="ui-effects-transfer"></div>').appendTo(document.body).addClass(a.options.className).css({top:d.top,left:d.left,height:b.innerHeight(),width:b.innerWidth(),position:"absolute"}).animate(c,a.duration,a.options.easing,function(){f.remove();a.callback&&a.callback.apply(b[0],arguments);
b.dequeue()})})}})(jQuery);
(function(c){c.widget("ui.accordion",{options:{active:0,animated:"slide",autoHeight:true,clearStyle:false,collapsible:false,event:"click",fillSpace:false,header:"> li > :first-child,> :not(li):even",icons:{header:"ui-icon-triangle-1-e",headerSelected:"ui-icon-triangle-1-s"},navigation:false,navigationFilter:function(){return this.href.toLowerCase()==location.href.toLowerCase()}},_create:function(){var a=this.options,b=this;this.running=0;this.element.addClass("ui-accordion ui-widget ui-helper-reset");
this.element[0].nodeName=="UL"&&this.element.children("li").addClass("ui-accordion-li-fix");this.headers=this.element.find(a.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all").bind("mouseenter.accordion",function(){c(this).addClass("ui-state-hover")}).bind("mouseleave.accordion",function(){c(this).removeClass("ui-state-hover")}).bind("focus.accordion",function(){c(this).addClass("ui-state-focus")}).bind("blur.accordion",function(){c(this).removeClass("ui-state-focus")});
this.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom");if(a.navigation){var d=this.element.find("a").filter(a.navigationFilter);if(d.length){var f=d.closest(".ui-accordion-header");this.active=f.length?f:d.closest(".ui-accordion-content").prev()}}this.active=this._findActive(this.active||a.active).toggleClass("ui-state-default").toggleClass("ui-state-active").toggleClass("ui-corner-all").toggleClass("ui-corner-top");this.active.next().addClass("ui-accordion-content-active");
this._createIcons();this.resize();this.element.attr("role","tablist");this.headers.attr("role","tab").bind("keydown",function(g){return b._keydown(g)}).next().attr("role","tabpanel");this.headers.not(this.active||"").attr("aria-expanded","false").attr("tabIndex","-1").next().hide();this.active.length?this.active.attr("aria-expanded","true").attr("tabIndex","0"):this.headers.eq(0).attr("tabIndex","0");c.browser.safari||this.headers.find("a").attr("tabIndex","-1");a.event&&this.headers.bind(a.event+
".accordion",function(g){b._clickHandler.call(b,g,this);g.preventDefault()})},_createIcons:function(){var a=this.options;if(a.icons){c("<span/>").addClass("ui-icon "+a.icons.header).prependTo(this.headers);this.active.find(".ui-icon").toggleClass(a.icons.header).toggleClass(a.icons.headerSelected);this.element.addClass("ui-accordion-icons")}},_destroyIcons:function(){this.headers.children(".ui-icon").remove();this.element.removeClass("ui-accordion-icons")},destroy:function(){var a=this.options;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role").unbind(".accordion").removeData("accordion");
this.headers.unbind(".accordion").removeClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("tabIndex");this.headers.find("a").removeAttr("tabIndex");this._destroyIcons();var b=this.headers.next().css("display","").removeAttr("role").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active");if(a.autoHeight||a.fillHeight)b.css("height",
"");return this},_setOption:function(a,b){c.Widget.prototype._setOption.apply(this,arguments);a=="active"&&this.activate(b);if(a=="icons"){this._destroyIcons();b&&this._createIcons()}},_keydown:function(a){var b=c.ui.keyCode;if(!(this.options.disabled||a.altKey||a.ctrlKey)){var d=this.headers.length,f=this.headers.index(a.target),g=false;switch(a.keyCode){case b.RIGHT:case b.DOWN:g=this.headers[(f+1)%d];break;case b.LEFT:case b.UP:g=this.headers[(f-1+d)%d];break;case b.SPACE:case b.ENTER:this._clickHandler({target:a.target},
a.target);a.preventDefault()}if(g){c(a.target).attr("tabIndex","-1");c(g).attr("tabIndex","0");g.focus();return false}return true}},resize:function(){var a=this.options,b;if(a.fillSpace){if(c.browser.msie){var d=this.element.parent().css("overflow");this.element.parent().css("overflow","hidden")}b=this.element.parent().height();c.browser.msie&&this.element.parent().css("overflow",d);this.headers.each(function(){b-=c(this).outerHeight(true)});this.headers.next().each(function(){c(this).height(Math.max(0,
b-c(this).innerHeight()+c(this).height()))}).css("overflow","auto")}else if(a.autoHeight){b=0;this.headers.next().each(function(){b=Math.max(b,c(this).height())}).height(b)}return this},activate:function(a){this.options.active=a;a=this._findActive(a)[0];this._clickHandler({target:a},a);return this},_findActive:function(a){return a?typeof a=="number"?this.headers.filter(":eq("+a+")"):this.headers.not(this.headers.not(a)):a===false?c([]):this.headers.filter(":eq(0)")},_clickHandler:function(a,b){var d=
this.options;if(!d.disabled)if(a.target){a=c(a.currentTarget||b);b=a[0]==this.active[0];d.active=d.collapsible&&b?false:c(".ui-accordion-header",this.element).index(a);if(!(this.running||!d.collapsible&&b)){this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").find(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header);if(!b){a.removeClass("ui-state-default ui-corner-all").addClass("ui-state-active ui-corner-top").find(".ui-icon").removeClass(d.icons.header).addClass(d.icons.headerSelected);
a.next().addClass("ui-accordion-content-active")}e=a.next();f=this.active.next();g={options:d,newHeader:b&&d.collapsible?c([]):a,oldHeader:this.active,newContent:b&&d.collapsible?c([]):e,oldContent:f};d=this.headers.index(this.active[0])>this.headers.index(a[0]);this.active=b?c([]):a;this._toggle(e,f,g,b,d)}}else if(d.collapsible){this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").find(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header);
this.active.next().addClass("ui-accordion-content-active");var f=this.active.next(),g={options:d,newHeader:c([]),oldHeader:d.active,newContent:c([]),oldContent:f},e=this.active=c([]);this._toggle(e,f,g)}},_toggle:function(a,b,d,f,g){var e=this.options,k=this;this.toShow=a;this.toHide=b;this.data=d;var i=function(){if(k)return k._completed.apply(k,arguments)};this._trigger("changestart",null,this.data);this.running=b.size()===0?a.size():b.size();if(e.animated){d={};d=e.collapsible&&f?{toShow:c([]),
toHide:b,complete:i,down:g,autoHeight:e.autoHeight||e.fillSpace}:{toShow:a,toHide:b,complete:i,down:g,autoHeight:e.autoHeight||e.fillSpace};if(!e.proxied)e.proxied=e.animated;if(!e.proxiedDuration)e.proxiedDuration=e.duration;e.animated=c.isFunction(e.proxied)?e.proxied(d):e.proxied;e.duration=c.isFunction(e.proxiedDuration)?e.proxiedDuration(d):e.proxiedDuration;f=c.ui.accordion.animations;var h=e.duration,j=e.animated;if(j&&!f[j]&&!c.easing[j])j="slide";f[j]||(f[j]=function(l){this.slide(l,{easing:j,
duration:h||700})});f[j](d)}else{if(e.collapsible&&f)a.toggle();else{b.hide();a.show()}i(true)}b.prev().attr("aria-expanded","false").attr("tabIndex","-1").blur();a.prev().attr("aria-expanded","true").attr("tabIndex","0").focus()},_completed:function(a){var b=this.options;this.running=a?0:--this.running;if(!this.running){b.clearStyle&&this.toShow.add(this.toHide).css({height:"",overflow:""});this.toHide.removeClass("ui-accordion-content-active");this._trigger("change",null,this.data)}}});c.extend(c.ui.accordion,
{version:"1.8.1",animations:{slide:function(a,b){a=c.extend({easing:"swing",duration:300},a,b);if(a.toHide.size())if(a.toShow.size()){var d=a.toShow.css("overflow"),f=0,g={},e={},k;b=a.toShow;k=b[0].style.width;b.width(parseInt(b.parent().width(),10)-parseInt(b.css("paddingLeft"),10)-parseInt(b.css("paddingRight"),10)-(parseInt(b.css("borderLeftWidth"),10)||0)-(parseInt(b.css("borderRightWidth"),10)||0));c.each(["height","paddingTop","paddingBottom"],function(i,h){e[h]="hide";i=(""+c.css(a.toShow[0],
h)).match(/^([\d+-.]+)(.*)$/);g[h]={value:i[1],unit:i[2]||"px"}});a.toShow.css({height:0,overflow:"hidden"}).show();a.toHide.filter(":hidden").each(a.complete).end().filter(":visible").animate(e,{step:function(i,h){if(h.prop=="height")f=h.end-h.start===0?0:(h.now-h.start)/(h.end-h.start);a.toShow[0].style[h.prop]=f*g[h.prop].value+g[h.prop].unit},duration:a.duration,easing:a.easing,complete:function(){a.autoHeight||a.toShow.css("height","");a.toShow.css("width",k);a.toShow.css({overflow:d});a.complete()}})}else a.toHide.animate({height:"hide"},
a);else a.toShow.animate({height:"show"},a)},bounceslide:function(a){this.slide(a,{easing:a.down?"easeOutBounce":"swing",duration:a.down?1E3:200})}}})})(jQuery);
(function(e){e.widget("ui.autocomplete",{options:{minLength:1,delay:300},_create:function(){var a=this,b=this.element[0].ownerDocument;this.element.addClass("ui-autocomplete-input").attr("autocomplete","off").attr({role:"textbox","aria-autocomplete":"list","aria-haspopup":"true"}).bind("keydown.autocomplete",function(c){var d=e.ui.keyCode;switch(c.keyCode){case d.PAGE_UP:a._move("previousPage",c);break;case d.PAGE_DOWN:a._move("nextPage",c);break;case d.UP:a._move("previous",c);c.preventDefault();
break;case d.DOWN:a._move("next",c);c.preventDefault();break;case d.ENTER:a.menu.active&&c.preventDefault();case d.TAB:if(!a.menu.active)return;a.menu.select(c);break;case d.ESCAPE:a.element.val(a.term);a.close(c);break;case d.LEFT:case d.RIGHT:case d.SHIFT:case d.CONTROL:case d.ALT:break;default:clearTimeout(a.searching);a.searching=setTimeout(function(){a.search(null,c)},a.options.delay);break}}).bind("focus.autocomplete",function(){a.selectedItem=null;a.previous=a.element.val()}).bind("blur.autocomplete",
function(c){clearTimeout(a.searching);a.closing=setTimeout(function(){a.close(c);a._change(c)},150)});this._initSource();this.response=function(){return a._response.apply(a,arguments)};this.menu=e("<ul></ul>").addClass("ui-autocomplete").appendTo("body",b).menu({focus:function(c,d){d=d.item.data("item.autocomplete");false!==a._trigger("focus",null,{item:d})&&/^key/.test(c.originalEvent.type)&&a.element.val(d.value)},selected:function(c,d){d=d.item.data("item.autocomplete");false!==a._trigger("select",
c,{item:d})&&a.element.val(d.value);a.close(c);c=a.previous;if(a.element[0]!==b.activeElement){a.element.focus();a.previous=c}a.selectedItem=d},blur:function(){a.menu.element.is(":visible")&&a.element.val(a.term)}}).zIndex(this.element.zIndex()+1).css({top:0,left:0}).hide().data("menu");e.fn.bgiframe&&this.menu.element.bgiframe()},destroy:function(){this.element.removeClass("ui-autocomplete-input").removeAttr("autocomplete").removeAttr("role").removeAttr("aria-autocomplete").removeAttr("aria-haspopup");
this.menu.element.remove();e.Widget.prototype.destroy.call(this)},_setOption:function(a){e.Widget.prototype._setOption.apply(this,arguments);a==="source"&&this._initSource()},_initSource:function(){var a,b;if(e.isArray(this.options.source)){a=this.options.source;this.source=function(c,d){d(e.ui.autocomplete.filter(a,c.term))}}else if(typeof this.options.source==="string"){b=this.options.source;this.source=function(c,d){e.getJSON(b,c,d)}}else this.source=this.options.source},search:function(a,b){a=
a!=null?a:this.element.val();if(a.length<this.options.minLength)return this.close(b);clearTimeout(this.closing);if(this._trigger("search")!==false)return this._search(a)},_search:function(a){this.term=this.element.addClass("ui-autocomplete-loading").val();this.source({term:a},this.response)},_response:function(a){if(a.length){a=this._normalize(a);this._suggest(a);this._trigger("open")}else this.close();this.element.removeClass("ui-autocomplete-loading")},close:function(a){clearTimeout(this.closing);
if(this.menu.element.is(":visible")){this._trigger("close",a);this.menu.element.hide();this.menu.deactivate()}},_change:function(a){this.previous!==this.element.val()&&this._trigger("change",a,{item:this.selectedItem})},_normalize:function(a){if(a.length&&a[0].label&&a[0].value)return a;return e.map(a,function(b){if(typeof b==="string")return{label:b,value:b};return e.extend({label:b.label||b.value,value:b.value||b.label},b)})},_suggest:function(a){var b=this.menu.element.empty().zIndex(this.element.zIndex()+
1),c;this._renderMenu(b,a);this.menu.deactivate();this.menu.refresh();this.menu.element.show().position({my:"left top",at:"left bottom",of:this.element,collision:"none"});a=b.width("").width();c=this.element.width();b.width(Math.max(a,c))},_renderMenu:function(a,b){var c=this;e.each(b,function(d,f){c._renderItem(a,f)})},_renderItem:function(a,b){return e("<li></li>").data("item.autocomplete",b).append("<a>"+b.label+"</a>").appendTo(a)},_move:function(a,b){if(this.menu.element.is(":visible"))if(this.menu.first()&&
/^previous/.test(a)||this.menu.last()&&/^next/.test(a)){this.element.val(this.term);this.menu.deactivate()}else this.menu[a](b);else this.search(null,b)},widget:function(){return this.menu.element}});e.extend(e.ui.autocomplete,{escapeRegex:function(a){return a.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi,"\\$1")},filter:function(a,b){var c=new RegExp(e.ui.autocomplete.escapeRegex(b),"i");return e.grep(a,function(d){return c.test(d.label||d.value||d)})}})})(jQuery);
(function(e){e.widget("ui.menu",{_create:function(){var a=this;this.element.addClass("ui-menu ui-widget ui-widget-content ui-corner-all").attr({role:"listbox","aria-activedescendant":"ui-active-menuitem"}).click(function(b){if(e(b.target).closest(".ui-menu-item a").length){b.preventDefault();a.select(b)}});this.refresh()},refresh:function(){var a=this;this.element.children("li:not(.ui-menu-item):has(a)").addClass("ui-menu-item").attr("role","menuitem").children("a").addClass("ui-corner-all").attr("tabindex",
-1).mouseenter(function(b){a.activate(b,e(this).parent())}).mouseleave(function(){a.deactivate()})},activate:function(a,b){this.deactivate();if(this.hasScroll()){var c=b.offset().top-this.element.offset().top,d=this.element.attr("scrollTop"),f=this.element.height();if(c<0)this.element.attr("scrollTop",d+c);else c>f&&this.element.attr("scrollTop",d+c-f+b.height())}this.active=b.eq(0).children("a").addClass("ui-state-hover").attr("id","ui-active-menuitem").end();this._trigger("focus",a,{item:b})},deactivate:function(){if(this.active){this.active.children("a").removeClass("ui-state-hover").removeAttr("id");
this._trigger("blur");this.active=null}},next:function(a){this.move("next",".ui-menu-item:first",a)},previous:function(a){this.move("prev",".ui-menu-item:last",a)},first:function(){return this.active&&!this.active.prev().length},last:function(){return this.active&&!this.active.next().length},move:function(a,b,c){if(this.active){a=this.active[a+"All"](".ui-menu-item").eq(0);a.length?this.activate(c,a):this.activate(c,this.element.children(b))}else this.activate(c,this.element.children(b))},nextPage:function(a){if(this.hasScroll())if(!this.active||
this.last())this.activate(a,this.element.children(":first"));else{var b=this.active.offset().top,c=this.element.height(),d=this.element.children("li").filter(function(){var f=e(this).offset().top-b-c+e(this).height();return f<10&&f>-10});d.length||(d=this.element.children(":last"));this.activate(a,d)}else this.activate(a,this.element.children(!this.active||this.last()?":first":":last"))},previousPage:function(a){if(this.hasScroll())if(!this.active||this.first())this.activate(a,this.element.children(":last"));
else{var b=this.active.offset().top,c=this.element.height();result=this.element.children("li").filter(function(){var d=e(this).offset().top-b+c-e(this).height();return d<10&&d>-10});result.length||(result=this.element.children(":first"));this.activate(a,result)}else this.activate(a,this.element.children(!this.active||this.first()?":last":":first"))},hasScroll:function(){return this.element.height()<this.element.attr("scrollHeight")},select:function(a){this._trigger("selected",a,{item:this.active})}})})(jQuery);
(function(a){var g,i=function(b){a(":ui-button",b.target.form).each(function(){var c=a(this).data("button");setTimeout(function(){c.refresh()},1)})},h=function(b){var c=b.name,d=b.form,e=a([]);if(c)e=d?a(d).find("[name='"+c+"']"):a("[name='"+c+"']",b.ownerDocument).filter(function(){return!this.form});return e};a.widget("ui.button",{options:{text:true,label:null,icons:{primary:null,secondary:null}},_create:function(){this.element.closest("form").unbind("reset.button").bind("reset.button",i);this._determineButtonType();
this.hasTitle=!!this.buttonElement.attr("title");var b=this,c=this.options,d=this.type==="checkbox"||this.type==="radio",e="ui-state-hover"+(!d?" ui-state-active":"");if(c.label===null)c.label=this.buttonElement.html();if(this.element.is(":disabled"))c.disabled=true;this.buttonElement.addClass("ui-button ui-widget ui-state-default ui-corner-all").attr("role","button").bind("mouseenter.button",function(){if(!c.disabled){a(this).addClass("ui-state-hover");this===g&&a(this).addClass("ui-state-active")}}).bind("mouseleave.button",
function(){c.disabled||a(this).removeClass(e)}).bind("focus.button",function(){a(this).addClass("ui-state-focus")}).bind("blur.button",function(){a(this).removeClass("ui-state-focus")});d&&this.element.bind("change.button",function(){b.refresh()});if(this.type==="checkbox")this.buttonElement.bind("click.button",function(){if(c.disabled)return false;a(this).toggleClass("ui-state-active");b.buttonElement.attr("aria-pressed",b.element[0].checked)});else if(this.type==="radio")this.buttonElement.bind("click.button",
function(){if(c.disabled)return false;a(this).addClass("ui-state-active");b.buttonElement.attr("aria-pressed",true);var f=b.element[0];h(f).not(f).map(function(){return a(this).button("widget")[0]}).removeClass("ui-state-active").attr("aria-pressed",false)});else{this.buttonElement.bind("mousedown.button",function(){if(c.disabled)return false;a(this).addClass("ui-state-active");g=this;a(document).one("mouseup",function(){g=null})}).bind("mouseup.button",function(){if(c.disabled)return false;a(this).removeClass("ui-state-active")}).bind("keydown.button",
function(f){if(c.disabled)return false;if(f.keyCode==a.ui.keyCode.SPACE||f.keyCode==a.ui.keyCode.ENTER)a(this).addClass("ui-state-active")}).bind("keyup.button",function(){a(this).removeClass("ui-state-active")});this.buttonElement.is("a")&&this.buttonElement.keyup(function(f){f.keyCode===a.ui.keyCode.SPACE&&a(this).click()})}this._setOption("disabled",c.disabled)},_determineButtonType:function(){this.type=this.element.is(":checkbox")?"checkbox":this.element.is(":radio")?"radio":this.element.is("input")?
"input":"button";if(this.type==="checkbox"||this.type==="radio"){this.buttonElement=this.element.parents().last().find("[for="+this.element.attr("id")+"]");this.element.addClass("ui-helper-hidden-accessible");var b=this.element.is(":checked");b&&this.buttonElement.addClass("ui-state-active");this.buttonElement.attr("aria-pressed",b)}else this.buttonElement=this.element},widget:function(){return this.buttonElement},destroy:function(){this.element.removeClass("ui-helper-hidden-accessible");this.buttonElement.removeClass("ui-button ui-widget ui-state-default ui-corner-all ui-state-hover ui-state-active ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon ui-button-text-only").removeAttr("role").removeAttr("aria-pressed").html(this.buttonElement.find(".ui-button-text").html());
this.hasTitle||this.buttonElement.removeAttr("title");a.Widget.prototype.destroy.call(this)},_setOption:function(b,c){a.Widget.prototype._setOption.apply(this,arguments);if(b==="disabled")c?this.element.attr("disabled",true):this.element.removeAttr("disabled");this._resetButton()},refresh:function(){var b=this.element.is(":disabled");b!==this.options.disabled&&this._setOption("disabled",b);if(this.type==="radio")h(this.element[0]).each(function(){a(this).is(":checked")?a(this).button("widget").addClass("ui-state-active").attr("aria-pressed",
true):a(this).button("widget").removeClass("ui-state-active").attr("aria-pressed",false)});else if(this.type==="checkbox")this.element.is(":checked")?this.buttonElement.addClass("ui-state-active").attr("aria-pressed",true):this.buttonElement.removeClass("ui-state-active").attr("aria-pressed",false)},_resetButton:function(){if(this.type==="input")this.options.label&&this.element.val(this.options.label);else{var b=this.buttonElement,c=a("<span></span>").addClass("ui-button-text").html(this.options.label).appendTo(b.empty()).text(),
d=this.options.icons,e=d.primary&&d.secondary;if(d.primary||d.secondary){b.addClass("ui-button-text-icon"+(e?"s":""));d.primary&&b.prepend("<span class='ui-button-icon-primary ui-icon "+d.primary+"'></span>");d.secondary&&b.append("<span class='ui-button-icon-secondary ui-icon "+d.secondary+"'></span>");if(!this.options.text){b.addClass(e?"ui-button-icons-only":"ui-button-icon-only").removeClass("ui-button-text-icons ui-button-text-icon");this.hasTitle||b.attr("title",c)}}else b.addClass("ui-button-text-only")}}});
a.widget("ui.buttonset",{_create:function(){this.element.addClass("ui-buttonset");this._init()},_init:function(){this.refresh()},_setOption:function(b,c){b==="disabled"&&this.buttons.button("option",b,c);a.Widget.prototype._setOption.apply(this,arguments)},refresh:function(){this.buttons=this.element.find(":button, :submit, :reset, :checkbox, :radio, a, :data(button)").filter(":ui-button").button("refresh").end().not(":ui-button").button().end().map(function(){return a(this).button("widget")[0]}).removeClass("ui-corner-all ui-corner-left ui-corner-right").filter(":first").addClass("ui-corner-left").end().filter(":last").addClass("ui-corner-right").end().end()},
destroy:function(){this.element.removeClass("ui-buttonset");this.buttons.map(function(){return a(this).button("widget")[0]}).removeClass("ui-corner-left ui-corner-right").end().button("destroy");a.Widget.prototype.destroy.call(this)}})})(jQuery);
(function(d){function J(){this.debug=false;this._curInst=null;this._keyEvent=false;this._disabledInputs=[];this._inDialog=this._datepickerShowing=false;this._mainDivId="ui-datepicker-div";this._inlineClass="ui-datepicker-inline";this._appendClass="ui-datepicker-append";this._triggerClass="ui-datepicker-trigger";this._dialogClass="ui-datepicker-dialog";this._disableClass="ui-datepicker-disabled";this._unselectableClass="ui-datepicker-unselectable";this._currentClass="ui-datepicker-current-day";this._dayOverClass=
"ui-datepicker-days-cell-over";this.regional=[];this.regional[""]={closeText:"Done",prevText:"Prev",nextText:"Next",currentText:"Today",monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayNamesMin:["Su",
"Mo","Tu","We","Th","Fr","Sa"],weekHeader:"Wk",dateFormat:"mm/dd/yy",firstDay:0,isRTL:false,showMonthAfterYear:false,yearSuffix:""};this._defaults={showOn:"focus",showAnim:"show",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:false,hideIfNoPrevNext:false,navigationAsDateFormat:false,gotoCurrent:false,changeMonth:false,changeYear:false,yearRange:"c-10:c+10",showOtherMonths:false,selectOtherMonths:false,showWeek:false,calculateWeek:this.iso8601Week,shortYearCutoff:"+10",
minDate:null,maxDate:null,duration:"_default",beforeShowDay:null,beforeShow:null,onSelect:null,onChangeMonthYear:null,onClose:null,numberOfMonths:1,showCurrentAtPos:0,stepMonths:1,stepBigMonths:12,altField:"",altFormat:"",constrainInput:true,showButtonPanel:false,autoSize:false};d.extend(this._defaults,this.regional[""]);this.dpDiv=d('<div id="'+this._mainDivId+'" class="ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all ui-helper-hidden-accessible"></div>')}function E(a,b){d.extend(a,
b);for(var c in b)if(b[c]==null||b[c]==undefined)a[c]=b[c];return a}d.extend(d.ui,{datepicker:{version:"1.8.1"}});var y=(new Date).getTime();d.extend(J.prototype,{markerClassName:"hasDatepicker",log:function(){this.debug&&console.log.apply("",arguments)},_widgetDatepicker:function(){return this.dpDiv},setDefaults:function(a){E(this._defaults,a||{});return this},_attachDatepicker:function(a,b){var c=null;for(var e in this._defaults){var f=a.getAttribute("date:"+e);if(f){c=c||{};try{c[e]=eval(f)}catch(h){c[e]=
f}}}e=a.nodeName.toLowerCase();f=e=="div"||e=="span";if(!a.id)a.id="dp"+ ++this.uuid;var i=this._newInst(d(a),f);i.settings=d.extend({},b||{},c||{});if(e=="input")this._connectDatepicker(a,i);else f&&this._inlineDatepicker(a,i)},_newInst:function(a,b){return{id:a[0].id.replace(/([^A-Za-z0-9_])/g,"\\\\$1"),input:a,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:b,dpDiv:!b?this.dpDiv:d('<div class="'+this._inlineClass+' ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>')}},
_connectDatepicker:function(a,b){var c=d(a);b.append=d([]);b.trigger=d([]);if(!c.hasClass(this.markerClassName)){this._attachments(c,b);c.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).keyup(this._doKeyUp).bind("setData.datepicker",function(e,f,h){b.settings[f]=h}).bind("getData.datepicker",function(e,f){return this._get(b,f)});this._autoSize(b);d.data(a,"datepicker",b)}},_attachments:function(a,b){var c=this._get(b,"appendText"),e=this._get(b,"isRTL");b.append&&
b.append.remove();if(c){b.append=d('<span class="'+this._appendClass+'">'+c+"</span>");a[e?"before":"after"](b.append)}a.unbind("focus",this._showDatepicker);b.trigger&&b.trigger.remove();c=this._get(b,"showOn");if(c=="focus"||c=="both")a.focus(this._showDatepicker);if(c=="button"||c=="both"){c=this._get(b,"buttonText");var f=this._get(b,"buttonImage");b.trigger=d(this._get(b,"buttonImageOnly")?d("<img/>").addClass(this._triggerClass).attr({src:f,alt:c,title:c}):d('<button type="button"></button>').addClass(this._triggerClass).html(f==
""?c:d("<img/>").attr({src:f,alt:c,title:c})));a[e?"before":"after"](b.trigger);b.trigger.click(function(){d.datepicker._datepickerShowing&&d.datepicker._lastInput==a[0]?d.datepicker._hideDatepicker():d.datepicker._showDatepicker(a[0]);return false})}},_autoSize:function(a){if(this._get(a,"autoSize")&&!a.inline){var b=new Date(2009,11,20),c=this._get(a,"dateFormat");if(c.match(/[DM]/)){var e=function(f){for(var h=0,i=0,g=0;g<f.length;g++)if(f[g].length>h){h=f[g].length;i=g}return i};b.setMonth(e(this._get(a,
c.match(/MM/)?"monthNames":"monthNamesShort")));b.setDate(e(this._get(a,c.match(/DD/)?"dayNames":"dayNamesShort"))+20-b.getDay())}a.input.attr("size",this._formatDate(a,b).length)}},_inlineDatepicker:function(a,b){var c=d(a);if(!c.hasClass(this.markerClassName)){c.addClass(this.markerClassName).append(b.dpDiv).bind("setData.datepicker",function(e,f,h){b.settings[f]=h}).bind("getData.datepicker",function(e,f){return this._get(b,f)});d.data(a,"datepicker",b);this._setDate(b,this._getDefaultDate(b),
true);this._updateDatepicker(b);this._updateAlternate(b)}},_dialogDatepicker:function(a,b,c,e,f){a=this._dialogInst;if(!a){a="dp"+ ++this.uuid;this._dialogInput=d('<input type="text" id="'+a+'" style="position: absolute; top: -100px; width: 0px; z-index: -10;"/>');this._dialogInput.keydown(this._doKeyDown);d("body").append(this._dialogInput);a=this._dialogInst=this._newInst(this._dialogInput,false);a.settings={};d.data(this._dialogInput[0],"datepicker",a)}E(a.settings,e||{});b=b&&b.constructor==Date?
this._formatDate(a,b):b;this._dialogInput.val(b);this._pos=f?f.length?f:[f.pageX,f.pageY]:null;if(!this._pos)this._pos=[document.documentElement.clientWidth/2-100+(document.documentElement.scrollLeft||document.body.scrollLeft),document.documentElement.clientHeight/2-150+(document.documentElement.scrollTop||document.body.scrollTop)];this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px");a.settings.onSelect=c;this._inDialog=true;this.dpDiv.addClass(this._dialogClass);this._showDatepicker(this._dialogInput[0]);
d.blockUI&&d.blockUI(this.dpDiv);d.data(this._dialogInput[0],"datepicker",a);return this},_destroyDatepicker:function(a){var b=d(a),c=d.data(a,"datepicker");if(b.hasClass(this.markerClassName)){var e=a.nodeName.toLowerCase();d.removeData(a,"datepicker");if(e=="input"){c.append.remove();c.trigger.remove();b.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup",this._doKeyUp)}else if(e=="div"||e=="span")b.removeClass(this.markerClassName).empty()}},
_enableDatepicker:function(a){var b=d(a),c=d.data(a,"datepicker");if(b.hasClass(this.markerClassName)){var e=a.nodeName.toLowerCase();if(e=="input"){a.disabled=false;c.trigger.filter("button").each(function(){this.disabled=false}).end().filter("img").css({opacity:"1.0",cursor:""})}else if(e=="div"||e=="span")b.children("."+this._inlineClass).children().removeClass("ui-state-disabled");this._disabledInputs=d.map(this._disabledInputs,function(f){return f==a?null:f})}},_disableDatepicker:function(a){var b=
d(a),c=d.data(a,"datepicker");if(b.hasClass(this.markerClassName)){var e=a.nodeName.toLowerCase();if(e=="input"){a.disabled=true;c.trigger.filter("button").each(function(){this.disabled=true}).end().filter("img").css({opacity:"0.5",cursor:"default"})}else if(e=="div"||e=="span")b.children("."+this._inlineClass).children().addClass("ui-state-disabled");this._disabledInputs=d.map(this._disabledInputs,function(f){return f==a?null:f});this._disabledInputs[this._disabledInputs.length]=a}},_isDisabledDatepicker:function(a){if(!a)return false;
for(var b=0;b<this._disabledInputs.length;b++)if(this._disabledInputs[b]==a)return true;return false},_getInst:function(a){try{return d.data(a,"datepicker")}catch(b){throw"Missing instance data for this datepicker";}},_optionDatepicker:function(a,b,c){var e=this._getInst(a);if(arguments.length==2&&typeof b=="string")return b=="defaults"?d.extend({},d.datepicker._defaults):e?b=="all"?d.extend({},e.settings):this._get(e,b):null;var f=b||{};if(typeof b=="string"){f={};f[b]=c}if(e){this._curInst==e&&
this._hideDatepicker();var h=this._getDateDatepicker(a,true);E(e.settings,f);this._attachments(d(a),e);this._autoSize(e);this._setDateDatepicker(a,h);this._updateDatepicker(e)}},_changeDatepicker:function(a,b,c){this._optionDatepicker(a,b,c)},_refreshDatepicker:function(a){(a=this._getInst(a))&&this._updateDatepicker(a)},_setDateDatepicker:function(a,b){if(a=this._getInst(a)){this._setDate(a,b);this._updateDatepicker(a);this._updateAlternate(a)}},_getDateDatepicker:function(a,b){(a=this._getInst(a))&&
!a.inline&&this._setDateFromField(a,b);return a?this._getDate(a):null},_doKeyDown:function(a){var b=d.datepicker._getInst(a.target),c=true,e=b.dpDiv.is(".ui-datepicker-rtl");b._keyEvent=true;if(d.datepicker._datepickerShowing)switch(a.keyCode){case 9:d.datepicker._hideDatepicker();c=false;break;case 13:c=d("td."+d.datepicker._dayOverClass,b.dpDiv).add(d("td."+d.datepicker._currentClass,b.dpDiv));c[0]?d.datepicker._selectDay(a.target,b.selectedMonth,b.selectedYear,c[0]):d.datepicker._hideDatepicker();
return false;case 27:d.datepicker._hideDatepicker();break;case 33:d.datepicker._adjustDate(a.target,a.ctrlKey?-d.datepicker._get(b,"stepBigMonths"):-d.datepicker._get(b,"stepMonths"),"M");break;case 34:d.datepicker._adjustDate(a.target,a.ctrlKey?+d.datepicker._get(b,"stepBigMonths"):+d.datepicker._get(b,"stepMonths"),"M");break;case 35:if(a.ctrlKey||a.metaKey)d.datepicker._clearDate(a.target);c=a.ctrlKey||a.metaKey;break;case 36:if(a.ctrlKey||a.metaKey)d.datepicker._gotoToday(a.target);c=a.ctrlKey||
a.metaKey;break;case 37:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,e?+1:-1,"D");c=a.ctrlKey||a.metaKey;if(a.originalEvent.altKey)d.datepicker._adjustDate(a.target,a.ctrlKey?-d.datepicker._get(b,"stepBigMonths"):-d.datepicker._get(b,"stepMonths"),"M");break;case 38:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,-7,"D");c=a.ctrlKey||a.metaKey;break;case 39:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,e?-1:+1,"D");c=a.ctrlKey||a.metaKey;if(a.originalEvent.altKey)d.datepicker._adjustDate(a.target,
a.ctrlKey?+d.datepicker._get(b,"stepBigMonths"):+d.datepicker._get(b,"stepMonths"),"M");break;case 40:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,+7,"D");c=a.ctrlKey||a.metaKey;break;default:c=false}else if(a.keyCode==36&&a.ctrlKey)d.datepicker._showDatepicker(this);else c=false;if(c){a.preventDefault();a.stopPropagation()}},_doKeyPress:function(a){var b=d.datepicker._getInst(a.target);if(d.datepicker._get(b,"constrainInput")){b=d.datepicker._possibleChars(d.datepicker._get(b,"dateFormat"));
var c=String.fromCharCode(a.charCode==undefined?a.keyCode:a.charCode);return a.ctrlKey||c<" "||!b||b.indexOf(c)>-1}},_doKeyUp:function(a){a=d.datepicker._getInst(a.target);if(a.input.val()!=a.lastVal)try{if(d.datepicker.parseDate(d.datepicker._get(a,"dateFormat"),a.input?a.input.val():null,d.datepicker._getFormatConfig(a))){d.datepicker._setDateFromField(a);d.datepicker._updateAlternate(a);d.datepicker._updateDatepicker(a)}}catch(b){d.datepicker.log(b)}return true},_showDatepicker:function(a){a=a.target||
a;if(a.nodeName.toLowerCase()!="input")a=d("input",a.parentNode)[0];if(!(d.datepicker._isDisabledDatepicker(a)||d.datepicker._lastInput==a)){var b=d.datepicker._getInst(a);d.datepicker._curInst&&d.datepicker._curInst!=b&&d.datepicker._curInst.dpDiv.stop(true,true);var c=d.datepicker._get(b,"beforeShow");E(b.settings,c?c.apply(a,[a,b]):{});b.lastVal=null;d.datepicker._lastInput=a;d.datepicker._setDateFromField(b);if(d.datepicker._inDialog)a.value="";if(!d.datepicker._pos){d.datepicker._pos=d.datepicker._findPos(a);
d.datepicker._pos[1]+=a.offsetHeight}var e=false;d(a).parents().each(function(){e|=d(this).css("position")=="fixed";return!e});if(e&&d.browser.opera){d.datepicker._pos[0]-=document.documentElement.scrollLeft;d.datepicker._pos[1]-=document.documentElement.scrollTop}c={left:d.datepicker._pos[0],top:d.datepicker._pos[1]};d.datepicker._pos=null;b.dpDiv.css({position:"absolute",display:"block",top:"-1000px"});d.datepicker._updateDatepicker(b);c=d.datepicker._checkOffset(b,c,e);b.dpDiv.css({position:d.datepicker._inDialog&&
d.blockUI?"static":e?"fixed":"absolute",display:"none",left:c.left+"px",top:c.top+"px"});if(!b.inline){c=d.datepicker._get(b,"showAnim");var f=d.datepicker._get(b,"duration"),h=function(){d.datepicker._datepickerShowing=true;var i=d.datepicker._getBorders(b.dpDiv);b.dpDiv.find("iframe.ui-datepicker-cover").css({left:-i[0],top:-i[1],width:b.dpDiv.outerWidth(),height:b.dpDiv.outerHeight()})};b.dpDiv.zIndex(d(a).zIndex()+1);d.effects&&d.effects[c]?b.dpDiv.show(c,d.datepicker._get(b,"showOptions"),f,
h):b.dpDiv[c||"show"](c?f:null,h);if(!c||!f)h();b.input.is(":visible")&&!b.input.is(":disabled")&&b.input.focus();d.datepicker._curInst=b}}},_updateDatepicker:function(a){var b=this,c=d.datepicker._getBorders(a.dpDiv);a.dpDiv.empty().append(this._generateHTML(a)).find("iframe.ui-datepicker-cover").css({left:-c[0],top:-c[1],width:a.dpDiv.outerWidth(),height:a.dpDiv.outerHeight()}).end().find("button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a").bind("mouseout",function(){d(this).removeClass("ui-state-hover");
this.className.indexOf("ui-datepicker-prev")!=-1&&d(this).removeClass("ui-datepicker-prev-hover");this.className.indexOf("ui-datepicker-next")!=-1&&d(this).removeClass("ui-datepicker-next-hover")}).bind("mouseover",function(){if(!b._isDisabledDatepicker(a.inline?a.dpDiv.parent()[0]:a.input[0])){d(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover");d(this).addClass("ui-state-hover");this.className.indexOf("ui-datepicker-prev")!=-1&&d(this).addClass("ui-datepicker-prev-hover");
this.className.indexOf("ui-datepicker-next")!=-1&&d(this).addClass("ui-datepicker-next-hover")}}).end().find("."+this._dayOverClass+" a").trigger("mouseover").end();c=this._getNumberOfMonths(a);var e=c[1];e>1?a.dpDiv.addClass("ui-datepicker-multi-"+e).css("width",17*e+"em"):a.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");a.dpDiv[(c[0]!=1||c[1]!=1?"add":"remove")+"Class"]("ui-datepicker-multi");a.dpDiv[(this._get(a,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl");
a==d.datepicker._curInst&&d.datepicker._datepickerShowing&&a.input&&a.input.is(":visible")&&!a.input.is(":disabled")&&a.input.focus()},_getBorders:function(a){var b=function(c){return{thin:1,medium:2,thick:3}[c]||c};return[parseFloat(b(a.css("border-left-width"))),parseFloat(b(a.css("border-top-width")))]},_checkOffset:function(a,b,c){var e=a.dpDiv.outerWidth(),f=a.dpDiv.outerHeight(),h=a.input?a.input.outerWidth():0,i=a.input?a.input.outerHeight():0,g=document.documentElement.clientWidth+d(document).scrollLeft(),
k=document.documentElement.clientHeight+d(document).scrollTop();b.left-=this._get(a,"isRTL")?e-h:0;b.left-=c&&b.left==a.input.offset().left?d(document).scrollLeft():0;b.top-=c&&b.top==a.input.offset().top+i?d(document).scrollTop():0;b.left-=Math.min(b.left,b.left+e>g&&g>e?Math.abs(b.left+e-g):0);b.top-=Math.min(b.top,b.top+f>k&&k>f?Math.abs(f+i):0);return b},_findPos:function(a){for(var b=this._get(this._getInst(a),"isRTL");a&&(a.type=="hidden"||a.nodeType!=1);)a=a[b?"previousSibling":"nextSibling"];
a=d(a).offset();return[a.left,a.top]},_hideDatepicker:function(a){var b=this._curInst;if(!(!b||a&&b!=d.data(a,"datepicker")))if(this._datepickerShowing){a=this._get(b,"showAnim");var c=this._get(b,"duration"),e=function(){d.datepicker._tidyDialog(b);this._curInst=null};d.effects&&d.effects[a]?b.dpDiv.hide(a,d.datepicker._get(b,"showOptions"),c,e):b.dpDiv[a=="slideDown"?"slideUp":a=="fadeIn"?"fadeOut":"hide"](a?c:null,e);a||e();if(a=this._get(b,"onClose"))a.apply(b.input?b.input[0]:null,[b.input?b.input.val():
"",b]);this._datepickerShowing=false;this._lastInput=null;if(this._inDialog){this._dialogInput.css({position:"absolute",left:"0",top:"-100px"});if(d.blockUI){d.unblockUI();d("body").append(this.dpDiv)}}this._inDialog=false}},_tidyDialog:function(a){a.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")},_checkExternalClick:function(a){if(d.datepicker._curInst){a=d(a.target);a[0].id!=d.datepicker._mainDivId&&a.parents("#"+d.datepicker._mainDivId).length==0&&!a.hasClass(d.datepicker.markerClassName)&&
!a.hasClass(d.datepicker._triggerClass)&&d.datepicker._datepickerShowing&&!(d.datepicker._inDialog&&d.blockUI)&&d.datepicker._hideDatepicker()}},_adjustDate:function(a,b,c){a=d(a);var e=this._getInst(a[0]);if(!this._isDisabledDatepicker(a[0])){this._adjustInstDate(e,b+(c=="M"?this._get(e,"showCurrentAtPos"):0),c);this._updateDatepicker(e)}},_gotoToday:function(a){a=d(a);var b=this._getInst(a[0]);if(this._get(b,"gotoCurrent")&&b.currentDay){b.selectedDay=b.currentDay;b.drawMonth=b.selectedMonth=b.currentMonth;
b.drawYear=b.selectedYear=b.currentYear}else{var c=new Date;b.selectedDay=c.getDate();b.drawMonth=b.selectedMonth=c.getMonth();b.drawYear=b.selectedYear=c.getFullYear()}this._notifyChange(b);this._adjustDate(a)},_selectMonthYear:function(a,b,c){a=d(a);var e=this._getInst(a[0]);e._selectingMonthYear=false;e["selected"+(c=="M"?"Month":"Year")]=e["draw"+(c=="M"?"Month":"Year")]=parseInt(b.options[b.selectedIndex].value,10);this._notifyChange(e);this._adjustDate(a)},_clickMonthYear:function(a){a=this._getInst(d(a)[0]);
a.input&&a._selectingMonthYear&&!d.browser.msie&&a.input.focus();a._selectingMonthYear=!a._selectingMonthYear},_selectDay:function(a,b,c,e){var f=d(a);if(!(d(e).hasClass(this._unselectableClass)||this._isDisabledDatepicker(f[0]))){f=this._getInst(f[0]);f.selectedDay=f.currentDay=d("a",e).html();f.selectedMonth=f.currentMonth=b;f.selectedYear=f.currentYear=c;this._selectDate(a,this._formatDate(f,f.currentDay,f.currentMonth,f.currentYear))}},_clearDate:function(a){a=d(a);this._getInst(a[0]);this._selectDate(a,
"")},_selectDate:function(a,b){a=this._getInst(d(a)[0]);b=b!=null?b:this._formatDate(a);a.input&&a.input.val(b);this._updateAlternate(a);var c=this._get(a,"onSelect");if(c)c.apply(a.input?a.input[0]:null,[b,a]);else a.input&&a.input.trigger("change");if(a.inline)this._updateDatepicker(a);else{this._hideDatepicker();this._lastInput=a.input[0];typeof a.input[0]!="object"&&a.input.focus();this._lastInput=null}},_updateAlternate:function(a){var b=this._get(a,"altField");if(b){var c=this._get(a,"altFormat")||
this._get(a,"dateFormat"),e=this._getDate(a),f=this.formatDate(c,e,this._getFormatConfig(a));d(b).each(function(){d(this).val(f)})}},noWeekends:function(a){a=a.getDay();return[a>0&&a<6,""]},iso8601Week:function(a){a=new Date(a.getTime());a.setDate(a.getDate()+4-(a.getDay()||7));var b=a.getTime();a.setMonth(0);a.setDate(1);return Math.floor(Math.round((b-a)/864E5)/7)+1},parseDate:function(a,b,c){if(a==null||b==null)throw"Invalid arguments";b=typeof b=="object"?b.toString():b+"";if(b=="")return null;
for(var e=(c?c.shortYearCutoff:null)||this._defaults.shortYearCutoff,f=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,h=(c?c.dayNames:null)||this._defaults.dayNames,i=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort,g=(c?c.monthNames:null)||this._defaults.monthNames,k=c=-1,l=-1,u=-1,j=false,o=function(p){(p=z+1<a.length&&a.charAt(z+1)==p)&&z++;return p},m=function(p){o(p);p=new RegExp("^\\d{1,"+(p=="@"?14:p=="!"?20:p=="y"?4:p=="o"?3:2)+"}");p=b.substring(s).match(p);if(!p)throw"Missing number at position "+
s;s+=p[0].length;return parseInt(p[0],10)},n=function(p,w,G){p=o(p)?G:w;for(w=0;w<p.length;w++)if(b.substr(s,p[w].length)==p[w]){s+=p[w].length;return w+1}throw"Unknown name at position "+s;},r=function(){if(b.charAt(s)!=a.charAt(z))throw"Unexpected literal at position "+s;s++},s=0,z=0;z<a.length;z++)if(j)if(a.charAt(z)=="'"&&!o("'"))j=false;else r();else switch(a.charAt(z)){case "d":l=m("d");break;case "D":n("D",f,h);break;case "o":u=m("o");break;case "m":k=m("m");break;case "M":k=n("M",i,g);break;
case "y":c=m("y");break;case "@":var v=new Date(m("@"));c=v.getFullYear();k=v.getMonth()+1;l=v.getDate();break;case "!":v=new Date((m("!")-this._ticksTo1970)/1E4);c=v.getFullYear();k=v.getMonth()+1;l=v.getDate();break;case "'":if(o("'"))r();else j=true;break;default:r()}if(c==-1)c=(new Date).getFullYear();else if(c<100)c+=(new Date).getFullYear()-(new Date).getFullYear()%100+(c<=e?0:-100);if(u>-1){k=1;l=u;do{e=this._getDaysInMonth(c,k-1);if(l<=e)break;k++;l-=e}while(1)}v=this._daylightSavingAdjust(new Date(c,
k-1,l));if(v.getFullYear()!=c||v.getMonth()+1!=k||v.getDate()!=l)throw"Invalid date";return v},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925))*24*60*60*1E7,formatDate:function(a,b,c){if(!b)return"";var e=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,f=(c?
c.dayNames:null)||this._defaults.dayNames,h=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort;c=(c?c.monthNames:null)||this._defaults.monthNames;var i=function(o){(o=j+1<a.length&&a.charAt(j+1)==o)&&j++;return o},g=function(o,m,n){m=""+m;if(i(o))for(;m.length<n;)m="0"+m;return m},k=function(o,m,n,r){return i(o)?r[m]:n[m]},l="",u=false;if(b)for(var j=0;j<a.length;j++)if(u)if(a.charAt(j)=="'"&&!i("'"))u=false;else l+=a.charAt(j);else switch(a.charAt(j)){case "d":l+=g("d",b.getDate(),2);break;
case "D":l+=k("D",b.getDay(),e,f);break;case "o":l+=g("o",(b.getTime()-(new Date(b.getFullYear(),0,0)).getTime())/864E5,3);break;case "m":l+=g("m",b.getMonth()+1,2);break;case "M":l+=k("M",b.getMonth(),h,c);break;case "y":l+=i("y")?b.getFullYear():(b.getYear()%100<10?"0":"")+b.getYear()%100;break;case "@":l+=b.getTime();break;case "!":l+=b.getTime()*1E4+this._ticksTo1970;break;case "'":if(i("'"))l+="'";else u=true;break;default:l+=a.charAt(j)}return l},_possibleChars:function(a){for(var b="",c=false,
e=function(h){(h=f+1<a.length&&a.charAt(f+1)==h)&&f++;return h},f=0;f<a.length;f++)if(c)if(a.charAt(f)=="'"&&!e("'"))c=false;else b+=a.charAt(f);else switch(a.charAt(f)){case "d":case "m":case "y":case "@":b+="0123456789";break;case "D":case "M":return null;case "'":if(e("'"))b+="'";else c=true;break;default:b+=a.charAt(f)}return b},_get:function(a,b){return a.settings[b]!==undefined?a.settings[b]:this._defaults[b]},_setDateFromField:function(a,b){if(a.input.val()!=a.lastVal){var c=this._get(a,"dateFormat"),
e=a.lastVal=a.input?a.input.val():null,f,h;f=h=this._getDefaultDate(a);var i=this._getFormatConfig(a);try{f=this.parseDate(c,e,i)||h}catch(g){this.log(g);e=b?"":e}a.selectedDay=f.getDate();a.drawMonth=a.selectedMonth=f.getMonth();a.drawYear=a.selectedYear=f.getFullYear();a.currentDay=e?f.getDate():0;a.currentMonth=e?f.getMonth():0;a.currentYear=e?f.getFullYear():0;this._adjustInstDate(a)}},_getDefaultDate:function(a){return this._restrictMinMax(a,this._determineDate(a,this._get(a,"defaultDate"),new Date))},
_determineDate:function(a,b,c){var e=function(h){var i=new Date;i.setDate(i.getDate()+h);return i},f=function(h){try{return d.datepicker.parseDate(d.datepicker._get(a,"dateFormat"),h,d.datepicker._getFormatConfig(a))}catch(i){}var g=(h.toLowerCase().match(/^c/)?d.datepicker._getDate(a):null)||new Date,k=g.getFullYear(),l=g.getMonth();g=g.getDate();for(var u=/([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,j=u.exec(h);j;){switch(j[2]||"d"){case "d":case "D":g+=parseInt(j[1],10);break;case "w":case "W":g+=parseInt(j[1],
10)*7;break;case "m":case "M":l+=parseInt(j[1],10);g=Math.min(g,d.datepicker._getDaysInMonth(k,l));break;case "y":case "Y":k+=parseInt(j[1],10);g=Math.min(g,d.datepicker._getDaysInMonth(k,l));break}j=u.exec(h)}return new Date(k,l,g)};if(b=(b=b==null?c:typeof b=="string"?f(b):typeof b=="number"?isNaN(b)?c:e(b):b)&&b.toString()=="Invalid Date"?c:b){b.setHours(0);b.setMinutes(0);b.setSeconds(0);b.setMilliseconds(0)}return this._daylightSavingAdjust(b)},_daylightSavingAdjust:function(a){if(!a)return null;
a.setHours(a.getHours()>12?a.getHours()+2:0);return a},_setDate:function(a,b,c){var e=!b,f=a.selectedMonth,h=a.selectedYear;b=this._restrictMinMax(a,this._determineDate(a,b,new Date));a.selectedDay=a.currentDay=b.getDate();a.drawMonth=a.selectedMonth=a.currentMonth=b.getMonth();a.drawYear=a.selectedYear=a.currentYear=b.getFullYear();if((f!=a.selectedMonth||h!=a.selectedYear)&&!c)this._notifyChange(a);this._adjustInstDate(a);if(a.input)a.input.val(e?"":this._formatDate(a))},_getDate:function(a){return!a.currentYear||
a.input&&a.input.val()==""?null:this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay))},_generateHTML:function(a){var b=new Date;b=this._daylightSavingAdjust(new Date(b.getFullYear(),b.getMonth(),b.getDate()));var c=this._get(a,"isRTL"),e=this._get(a,"showButtonPanel"),f=this._get(a,"hideIfNoPrevNext"),h=this._get(a,"navigationAsDateFormat"),i=this._getNumberOfMonths(a),g=this._get(a,"showCurrentAtPos"),k=this._get(a,"stepMonths"),l=i[0]!=1||i[1]!=1,u=this._daylightSavingAdjust(!a.currentDay?
new Date(9999,9,9):new Date(a.currentYear,a.currentMonth,a.currentDay)),j=this._getMinMaxDate(a,"min"),o=this._getMinMaxDate(a,"max");g=a.drawMonth-g;var m=a.drawYear;if(g<0){g+=12;m--}if(o){var n=this._daylightSavingAdjust(new Date(o.getFullYear(),o.getMonth()-i[0]*i[1]+1,o.getDate()));for(n=j&&n<j?j:n;this._daylightSavingAdjust(new Date(m,g,1))>n;){g--;if(g<0){g=11;m--}}}a.drawMonth=g;a.drawYear=m;n=this._get(a,"prevText");n=!h?n:this.formatDate(n,this._daylightSavingAdjust(new Date(m,g-k,1)),this._getFormatConfig(a));
n=this._canAdjustMonth(a,-1,m,g)?'<a class="ui-datepicker-prev ui-corner-all" onclick="DP_jQuery_'+y+".datepicker._adjustDate('#"+a.id+"', -"+k+", 'M');\" title=\""+n+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"e":"w")+'">'+n+"</span></a>":f?"":'<a class="ui-datepicker-prev ui-corner-all ui-state-disabled" title="'+n+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"e":"w")+'">'+n+"</span></a>";var r=this._get(a,"nextText");r=!h?r:this.formatDate(r,this._daylightSavingAdjust(new Date(m,
g+k,1)),this._getFormatConfig(a));f=this._canAdjustMonth(a,+1,m,g)?'<a class="ui-datepicker-next ui-corner-all" onclick="DP_jQuery_'+y+".datepicker._adjustDate('#"+a.id+"', +"+k+", 'M');\" title=\""+r+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"w":"e")+'">'+r+"</span></a>":f?"":'<a class="ui-datepicker-next ui-corner-all ui-state-disabled" title="'+r+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"w":"e")+'">'+r+"</span></a>";k=this._get(a,"currentText");r=this._get(a,"gotoCurrent")&&
a.currentDay?u:b;k=!h?k:this.formatDate(k,r,this._getFormatConfig(a));h=!a.inline?'<button type="button" class="ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all" onclick="DP_jQuery_'+y+'.datepicker._hideDatepicker();">'+this._get(a,"closeText")+"</button>":"";e=e?'<div class="ui-datepicker-buttonpane ui-widget-content">'+(c?h:"")+(this._isInRange(a,r)?'<button type="button" class="ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all" onclick="DP_jQuery_'+
y+".datepicker._gotoToday('#"+a.id+"');\">"+k+"</button>":"")+(c?"":h)+"</div>":"";h=parseInt(this._get(a,"firstDay"),10);h=isNaN(h)?0:h;k=this._get(a,"showWeek");r=this._get(a,"dayNames");this._get(a,"dayNamesShort");var s=this._get(a,"dayNamesMin"),z=this._get(a,"monthNames"),v=this._get(a,"monthNamesShort"),p=this._get(a,"beforeShowDay"),w=this._get(a,"showOtherMonths"),G=this._get(a,"selectOtherMonths");this._get(a,"calculateWeek");for(var K=this._getDefaultDate(a),H="",C=0;C<i[0];C++){for(var L=
"",D=0;D<i[1];D++){var M=this._daylightSavingAdjust(new Date(m,g,a.selectedDay)),t=" ui-corner-all",x="";if(l){x+='<div class="ui-datepicker-group';if(i[1]>1)switch(D){case 0:x+=" ui-datepicker-group-first";t=" ui-corner-"+(c?"right":"left");break;case i[1]-1:x+=" ui-datepicker-group-last";t=" ui-corner-"+(c?"left":"right");break;default:x+=" ui-datepicker-group-middle";t="";break}x+='">'}x+='<div class="ui-datepicker-header ui-widget-header ui-helper-clearfix'+t+'">'+(/all|left/.test(t)&&C==0?c?
f:n:"")+(/all|right/.test(t)&&C==0?c?n:f:"")+this._generateMonthYearHeader(a,g,m,j,o,C>0||D>0,z,v)+'</div><table class="ui-datepicker-calendar"><thead><tr>';var A=k?'<th class="ui-datepicker-week-col">'+this._get(a,"weekHeader")+"</th>":"";for(t=0;t<7;t++){var q=(t+h)%7;A+="<th"+((t+h+6)%7>=5?' class="ui-datepicker-week-end"':"")+'><span title="'+r[q]+'">'+s[q]+"</span></th>"}x+=A+"</tr></thead><tbody>";A=this._getDaysInMonth(m,g);if(m==a.selectedYear&&g==a.selectedMonth)a.selectedDay=Math.min(a.selectedDay,
A);t=(this._getFirstDayOfMonth(m,g)-h+7)%7;A=l?6:Math.ceil((t+A)/7);q=this._daylightSavingAdjust(new Date(m,g,1-t));for(var N=0;N<A;N++){x+="<tr>";var O=!k?"":'<td class="ui-datepicker-week-col">'+this._get(a,"calculateWeek")(q)+"</td>";for(t=0;t<7;t++){var F=p?p.apply(a.input?a.input[0]:null,[q]):[true,""],B=q.getMonth()!=g,I=B&&!G||!F[0]||j&&q<j||o&&q>o;O+='<td class="'+((t+h+6)%7>=5?" ui-datepicker-week-end":"")+(B?" ui-datepicker-other-month":"")+(q.getTime()==M.getTime()&&g==a.selectedMonth&&
a._keyEvent||K.getTime()==q.getTime()&&K.getTime()==M.getTime()?" "+this._dayOverClass:"")+(I?" "+this._unselectableClass+" ui-state-disabled":"")+(B&&!w?"":" "+F[1]+(q.getTime()==u.getTime()?" "+this._currentClass:"")+(q.getTime()==b.getTime()?" ui-datepicker-today":""))+'"'+((!B||w)&&F[2]?' title="'+F[2]+'"':"")+(I?"":' onclick="DP_jQuery_'+y+".datepicker._selectDay('#"+a.id+"',"+q.getMonth()+","+q.getFullYear()+', this);return false;"')+">"+(B&&!w?"&#xa0;":I?'<span class="ui-state-default">'+q.getDate()+
"</span>":'<a class="ui-state-default'+(q.getTime()==b.getTime()?" ui-state-highlight":"")+(q.getTime()==u.getTime()?" ui-state-active":"")+(B?" ui-priority-secondary":"")+'" href="#">'+q.getDate()+"</a>")+"</td>";q.setDate(q.getDate()+1);q=this._daylightSavingAdjust(q)}x+=O+"</tr>"}g++;if(g>11){g=0;m++}x+="</tbody></table>"+(l?"</div>"+(i[0]>0&&D==i[1]-1?'<div class="ui-datepicker-row-break"></div>':""):"");L+=x}H+=L}H+=e+(d.browser.msie&&parseInt(d.browser.version,10)<7&&!a.inline?'<iframe src="javascript:false;" class="ui-datepicker-cover" frameborder="0"></iframe>':
"");a._keyEvent=false;return H},_generateMonthYearHeader:function(a,b,c,e,f,h,i,g){var k=this._get(a,"changeMonth"),l=this._get(a,"changeYear"),u=this._get(a,"showMonthAfterYear"),j='<div class="ui-datepicker-title">',o="";if(h||!k)o+='<span class="ui-datepicker-month">'+i[b]+"</span>";else{i=e&&e.getFullYear()==c;var m=f&&f.getFullYear()==c;o+='<select class="ui-datepicker-month" onchange="DP_jQuery_'+y+".datepicker._selectMonthYear('#"+a.id+"', this, 'M');\" onclick=\"DP_jQuery_"+y+".datepicker._clickMonthYear('#"+
a.id+"');\">";for(var n=0;n<12;n++)if((!i||n>=e.getMonth())&&(!m||n<=f.getMonth()))o+='<option value="'+n+'"'+(n==b?' selected="selected"':"")+">"+g[n]+"</option>";o+="</select>"}u||(j+=o+(h||!(k&&l)?"&#xa0;":""));if(h||!l)j+='<span class="ui-datepicker-year">'+c+"</span>";else{g=this._get(a,"yearRange").split(":");var r=(new Date).getFullYear();i=function(s){s=s.match(/c[+-].*/)?c+parseInt(s.substring(1),10):s.match(/[+-].*/)?r+parseInt(s,10):parseInt(s,10);return isNaN(s)?r:s};b=i(g[0]);g=Math.max(b,
i(g[1]||""));b=e?Math.max(b,e.getFullYear()):b;g=f?Math.min(g,f.getFullYear()):g;for(j+='<select class="ui-datepicker-year" onchange="DP_jQuery_'+y+".datepicker._selectMonthYear('#"+a.id+"', this, 'Y');\" onclick=\"DP_jQuery_"+y+".datepicker._clickMonthYear('#"+a.id+"');\">";b<=g;b++)j+='<option value="'+b+'"'+(b==c?' selected="selected"':"")+">"+b+"</option>";j+="</select>"}j+=this._get(a,"yearSuffix");if(u)j+=(h||!(k&&l)?"&#xa0;":"")+o;j+="</div>";return j},_adjustInstDate:function(a,b,c){var e=
a.drawYear+(c=="Y"?b:0),f=a.drawMonth+(c=="M"?b:0);b=Math.min(a.selectedDay,this._getDaysInMonth(e,f))+(c=="D"?b:0);e=this._restrictMinMax(a,this._daylightSavingAdjust(new Date(e,f,b)));a.selectedDay=e.getDate();a.drawMonth=a.selectedMonth=e.getMonth();a.drawYear=a.selectedYear=e.getFullYear();if(c=="M"||c=="Y")this._notifyChange(a)},_restrictMinMax:function(a,b){var c=this._getMinMaxDate(a,"min");a=this._getMinMaxDate(a,"max");b=c&&b<c?c:b;return b=a&&b>a?a:b},_notifyChange:function(a){var b=this._get(a,
"onChangeMonthYear");if(b)b.apply(a.input?a.input[0]:null,[a.selectedYear,a.selectedMonth+1,a])},_getNumberOfMonths:function(a){a=this._get(a,"numberOfMonths");return a==null?[1,1]:typeof a=="number"?[1,a]:a},_getMinMaxDate:function(a,b){return this._determineDate(a,this._get(a,b+"Date"),null)},_getDaysInMonth:function(a,b){return 32-(new Date(a,b,32)).getDate()},_getFirstDayOfMonth:function(a,b){return(new Date(a,b,1)).getDay()},_canAdjustMonth:function(a,b,c,e){var f=this._getNumberOfMonths(a);
c=this._daylightSavingAdjust(new Date(c,e+(b<0?b:f[0]*f[1]),1));b<0&&c.setDate(this._getDaysInMonth(c.getFullYear(),c.getMonth()));return this._isInRange(a,c)},_isInRange:function(a,b){var c=this._getMinMaxDate(a,"min");a=this._getMinMaxDate(a,"max");return(!c||b.getTime()>=c.getTime())&&(!a||b.getTime()<=a.getTime())},_getFormatConfig:function(a){var b=this._get(a,"shortYearCutoff");b=typeof b!="string"?b:(new Date).getFullYear()%100+parseInt(b,10);return{shortYearCutoff:b,dayNamesShort:this._get(a,
"dayNamesShort"),dayNames:this._get(a,"dayNames"),monthNamesShort:this._get(a,"monthNamesShort"),monthNames:this._get(a,"monthNames")}},_formatDate:function(a,b,c,e){if(!b){a.currentDay=a.selectedDay;a.currentMonth=a.selectedMonth;a.currentYear=a.selectedYear}b=b?typeof b=="object"?b:this._daylightSavingAdjust(new Date(e,c,b)):this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return this.formatDate(this._get(a,"dateFormat"),b,this._getFormatConfig(a))}});d.fn.datepicker=
function(a){if(!d.datepicker.initialized){d(document).mousedown(d.datepicker._checkExternalClick).find("body").append(d.datepicker.dpDiv);d.datepicker.initialized=true}var b=Array.prototype.slice.call(arguments,1);if(typeof a=="string"&&(a=="isDisabled"||a=="getDate"||a=="widget"))return d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this[0]].concat(b));if(a=="option"&&arguments.length==2&&typeof arguments[1]=="string")return d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this[0]].concat(b));
return this.each(function(){typeof a=="string"?d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this].concat(b)):d.datepicker._attachDatepicker(this,a)})};d.datepicker=new J;d.datepicker.initialized=false;d.datepicker.uuid=(new Date).getTime();d.datepicker.version="1.8.1";window["DP_jQuery_"+y]=d})(jQuery);
(function(c){c.widget("ui.dialog",{options:{autoOpen:true,buttons:{},closeOnEscape:true,closeText:"close",dialogClass:"",draggable:true,hide:null,height:"auto",maxHeight:false,maxWidth:false,minHeight:150,minWidth:150,modal:false,position:"center",resizable:true,show:null,stack:true,title:"",width:300,zIndex:1E3},_create:function(){this.originalTitle=this.element.attr("title");var a=this,b=a.options,d=b.title||a.originalTitle||"&#160;",e=c.ui.dialog.getTitleId(a.element),g=(a.uiDialog=c("<div></div>")).appendTo(document.body).hide().addClass("ui-dialog ui-widget ui-widget-content ui-corner-all "+
b.dialogClass).css({zIndex:b.zIndex}).attr("tabIndex",-1).css("outline",0).keydown(function(i){if(b.closeOnEscape&&i.keyCode&&i.keyCode===c.ui.keyCode.ESCAPE){a.close(i);i.preventDefault()}}).attr({role:"dialog","aria-labelledby":e}).mousedown(function(i){a.moveToTop(false,i)});a.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(g);var f=(a.uiDialogTitlebar=c("<div></div>")).addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(g),
h=c('<a href="#"></a>').addClass("ui-dialog-titlebar-close ui-corner-all").attr("role","button").hover(function(){h.addClass("ui-state-hover")},function(){h.removeClass("ui-state-hover")}).focus(function(){h.addClass("ui-state-focus")}).blur(function(){h.removeClass("ui-state-focus")}).click(function(i){a.close(i);return false}).appendTo(f);(a.uiDialogTitlebarCloseText=c("<span></span>")).addClass("ui-icon ui-icon-closethick").text(b.closeText).appendTo(h);c("<span></span>").addClass("ui-dialog-title").attr("id",
e).html(d).prependTo(f);if(c.isFunction(b.beforeclose)&&!c.isFunction(b.beforeClose))b.beforeClose=b.beforeclose;f.find("*").add(f).disableSelection();b.draggable&&c.fn.draggable&&a._makeDraggable();b.resizable&&c.fn.resizable&&a._makeResizable();a._createButtons(b.buttons);a._isOpen=false;c.fn.bgiframe&&g.bgiframe()},_init:function(){this.options.autoOpen&&this.open()},destroy:function(){var a=this;a.overlay&&a.overlay.destroy();a.uiDialog.hide();a.element.unbind(".dialog").removeData("dialog").removeClass("ui-dialog-content ui-widget-content").hide().appendTo("body");
a.uiDialog.remove();a.originalTitle&&a.element.attr("title",a.originalTitle);return a},widget:function(){return this.uiDialog},close:function(a){var b=this,d;if(false!==b._trigger("beforeClose",a)){b.overlay&&b.overlay.destroy();b.uiDialog.unbind("keypress.ui-dialog");b._isOpen=false;if(b.options.hide)b.uiDialog.hide(b.options.hide,function(){b._trigger("close",a)});else{b.uiDialog.hide();b._trigger("close",a)}c.ui.dialog.overlay.resize();if(b.options.modal){d=0;c(".ui-dialog").each(function(){if(this!==
b.uiDialog[0])d=Math.max(d,c(this).css("z-index"))});c.ui.dialog.maxZ=d}return b}},isOpen:function(){return this._isOpen},moveToTop:function(a,b){var d=this,e=d.options;if(e.modal&&!a||!e.stack&&!e.modal)return d._trigger("focus",b);if(e.zIndex>c.ui.dialog.maxZ)c.ui.dialog.maxZ=e.zIndex;if(d.overlay){c.ui.dialog.maxZ+=1;d.overlay.$el.css("z-index",c.ui.dialog.overlay.maxZ=c.ui.dialog.maxZ)}a={scrollTop:d.element.attr("scrollTop"),scrollLeft:d.element.attr("scrollLeft")};c.ui.dialog.maxZ+=1;d.uiDialog.css("z-index",
c.ui.dialog.maxZ);d.element.attr(a);d._trigger("focus",b);return d},open:function(){if(!this._isOpen){var a=this,b=a.options,d=a.uiDialog;a.overlay=b.modal?new c.ui.dialog.overlay(a):null;d.next().length&&d.appendTo("body");a._size();a._position(b.position);d.show(b.show);a.moveToTop(true);b.modal&&d.bind("keypress.ui-dialog",function(e){if(e.keyCode===c.ui.keyCode.TAB){var g=c(":tabbable",this),f=g.filter(":first");g=g.filter(":last");if(e.target===g[0]&&!e.shiftKey){f.focus(1);return false}else if(e.target===
f[0]&&e.shiftKey){g.focus(1);return false}}});c([]).add(d.find(".ui-dialog-content :tabbable:first")).add(d.find(".ui-dialog-buttonpane :tabbable:first")).add(d).filter(":first").focus();a._trigger("open");a._isOpen=true;return a}},_createButtons:function(a){var b=this,d=false,e=c("<div></div>").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix");b.uiDialog.find(".ui-dialog-buttonpane").remove();typeof a==="object"&&a!==null&&c.each(a,function(){return!(d=true)});if(d){c.each(a,
function(g,f){g=c('<button type="button"></button>').text(g).click(function(){f.apply(b.element[0],arguments)}).appendTo(e);c.fn.button&&g.button()});e.appendTo(b.uiDialog)}},_makeDraggable:function(){function a(f){return{position:f.position,offset:f.offset}}var b=this,d=b.options,e=c(document),g;b.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",handle:".ui-dialog-titlebar",containment:"document",start:function(f,h){g=d.height==="auto"?"auto":c(this).height();c(this).height(c(this).height()).addClass("ui-dialog-dragging");
b._trigger("dragStart",f,a(h))},drag:function(f,h){b._trigger("drag",f,a(h))},stop:function(f,h){d.position=[h.position.left-e.scrollLeft(),h.position.top-e.scrollTop()];c(this).removeClass("ui-dialog-dragging").height(g);b._trigger("dragStop",f,a(h));c.ui.dialog.overlay.resize()}})},_makeResizable:function(a){function b(f){return{originalPosition:f.originalPosition,originalSize:f.originalSize,position:f.position,size:f.size}}a=a===undefined?this.options.resizable:a;var d=this,e=d.options,g=d.uiDialog.css("position");
a=typeof a==="string"?a:"n,e,s,w,se,sw,ne,nw";d.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:d.element,maxWidth:e.maxWidth,maxHeight:e.maxHeight,minWidth:e.minWidth,minHeight:d._minHeight(),handles:a,start:function(f,h){c(this).addClass("ui-dialog-resizing");d._trigger("resizeStart",f,b(h))},resize:function(f,h){d._trigger("resize",f,b(h))},stop:function(f,h){c(this).removeClass("ui-dialog-resizing");e.height=c(this).height();e.width=c(this).width();d._trigger("resizeStop",
f,b(h));c.ui.dialog.overlay.resize()}}).css("position",g).find(".ui-resizable-se").addClass("ui-icon ui-icon-grip-diagonal-se")},_minHeight:function(){var a=this.options;return a.height==="auto"?a.minHeight:Math.min(a.minHeight,a.height)},_position:function(a){var b=[],d=[0,0];a=a||c.ui.dialog.prototype.options.position;if(typeof a==="string"||typeof a==="object"&&"0"in a){b=a.split?a.split(" "):[a[0],a[1]];if(b.length===1)b[1]=b[0];c.each(["left","top"],function(e,g){if(+b[e]===b[e]){d[e]=b[e];b[e]=
g}})}else if(typeof a==="object"){if("left"in a){b[0]="left";d[0]=a.left}else if("right"in a){b[0]="right";d[0]=-a.right}if("top"in a){b[1]="top";d[1]=a.top}else if("bottom"in a){b[1]="bottom";d[1]=-a.bottom}}(a=this.uiDialog.is(":visible"))||this.uiDialog.show();this.uiDialog.css({top:0,left:0}).position({my:b.join(" "),at:b.join(" "),offset:d.join(" "),of:window,collision:"fit",using:function(e){var g=c(this).css(e).offset().top;g<0&&c(this).css("top",e.top-g)}});a||this.uiDialog.hide()},_setOption:function(a,
b){var d=this,e=d.uiDialog,g=e.is(":data(resizable)"),f=false;switch(a){case "beforeclose":a="beforeClose";break;case "buttons":d._createButtons(b);break;case "closeText":d.uiDialogTitlebarCloseText.text(""+b);break;case "dialogClass":e.removeClass(d.options.dialogClass).addClass("ui-dialog ui-widget ui-widget-content ui-corner-all "+b);break;case "disabled":b?e.addClass("ui-dialog-disabled"):e.removeClass("ui-dialog-disabled");break;case "draggable":b?d._makeDraggable():e.draggable("destroy");break;
case "height":f=true;break;case "maxHeight":g&&e.resizable("option","maxHeight",b);f=true;break;case "maxWidth":g&&e.resizable("option","maxWidth",b);f=true;break;case "minHeight":g&&e.resizable("option","minHeight",b);f=true;break;case "minWidth":g&&e.resizable("option","minWidth",b);f=true;break;case "position":d._position(b);break;case "resizable":g&&!b&&e.resizable("destroy");g&&typeof b==="string"&&e.resizable("option","handles",b);!g&&b!==false&&d._makeResizable(b);break;case "title":c(".ui-dialog-title",
d.uiDialogTitlebar).html(""+(b||"&#160;"));break;case "width":f=true;break}c.Widget.prototype._setOption.apply(d,arguments);f&&d._size()},_size:function(){var a=this.options,b;this.element.css({width:"auto",minHeight:0,height:0});b=this.uiDialog.css({height:"auto",width:a.width}).height();this.element.css(a.height==="auto"?{minHeight:Math.max(a.minHeight-b,0),height:"auto"}:{minHeight:0,height:Math.max(a.height-b,0)}).show();this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option","minHeight",
this._minHeight())}});c.extend(c.ui.dialog,{version:"1.8.1",uuid:0,maxZ:0,getTitleId:function(a){a=a.attr("id");if(!a){this.uuid+=1;a=this.uuid}return"ui-dialog-title-"+a},overlay:function(a){this.$el=c.ui.dialog.overlay.create(a)}});c.extend(c.ui.dialog.overlay,{instances:[],oldInstances:[],maxZ:0,events:c.map("focus,mousedown,mouseup,keydown,keypress,click".split(","),function(a){return a+".dialog-overlay"}).join(" "),create:function(a){if(this.instances.length===0){setTimeout(function(){c.ui.dialog.overlay.instances.length&&
c(document).bind(c.ui.dialog.overlay.events,function(d){return c(d.target).zIndex()>=c.ui.dialog.overlay.maxZ})},1);c(document).bind("keydown.dialog-overlay",function(d){if(a.options.closeOnEscape&&d.keyCode&&d.keyCode===c.ui.keyCode.ESCAPE){a.close(d);d.preventDefault()}});c(window).bind("resize.dialog-overlay",c.ui.dialog.overlay.resize)}var b=(this.oldInstances.pop()||c("<div></div>").addClass("ui-widget-overlay")).appendTo(document.body).css({width:this.width(),height:this.height()});c.fn.bgiframe&&
b.bgiframe();this.instances.push(b);return b},destroy:function(a){this.oldInstances.push(this.instances.splice(c.inArray(a,this.instances),1)[0]);this.instances.length===0&&c([document,window]).unbind(".dialog-overlay");a.remove();var b=0;c.each(this.instances,function(){b=Math.max(b,this.css("z-index"))});this.maxZ=b},height:function(){var a,b;if(c.browser.msie&&c.browser.version<7){a=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight);b=Math.max(document.documentElement.offsetHeight,
document.body.offsetHeight);return a<b?c(window).height()+"px":a+"px"}else return c(document).height()+"px"},width:function(){var a,b;if(c.browser.msie&&c.browser.version<7){a=Math.max(document.documentElement.scrollWidth,document.body.scrollWidth);b=Math.max(document.documentElement.offsetWidth,document.body.offsetWidth);return a<b?c(window).width()+"px":a+"px"}else return c(document).width()+"px"},resize:function(){var a=c([]);c.each(c.ui.dialog.overlay.instances,function(){a=a.add(this)});a.css({width:0,
height:0}).css({width:c.ui.dialog.overlay.width(),height:c.ui.dialog.overlay.height()})}});c.extend(c.ui.dialog.overlay.prototype,{destroy:function(){c.ui.dialog.overlay.destroy(this.$el)}})})(jQuery);
(function(c){c.ui=c.ui||{};var m=/left|center|right/,n=/top|center|bottom/,p=c.fn.position,q=c.fn.offset;c.fn.position=function(a){if(!a||!a.of)return p.apply(this,arguments);a=c.extend({},a);var b=c(a.of),d=(a.collision||"flip").split(" "),e=a.offset?a.offset.split(" "):[0,0],g,h,i;if(a.of.nodeType===9){g=b.width();h=b.height();i={top:0,left:0}}else if(a.of.scrollTo&&a.of.document){g=b.width();h=b.height();i={top:b.scrollTop(),left:b.scrollLeft()}}else if(a.of.preventDefault){a.at="left top";g=h=
0;i={top:a.of.pageY,left:a.of.pageX}}else{g=b.outerWidth();h=b.outerHeight();i=b.offset()}c.each(["my","at"],function(){var f=(a[this]||"").split(" ");if(f.length===1)f=m.test(f[0])?f.concat(["center"]):n.test(f[0])?["center"].concat(f):["center","center"];f[0]=m.test(f[0])?f[0]:"center";f[1]=n.test(f[1])?f[1]:"center";a[this]=f});if(d.length===1)d[1]=d[0];e[0]=parseInt(e[0],10)||0;if(e.length===1)e[1]=e[0];e[1]=parseInt(e[1],10)||0;if(a.at[0]==="right")i.left+=g;else if(a.at[0]==="center")i.left+=
g/2;if(a.at[1]==="bottom")i.top+=h;else if(a.at[1]==="center")i.top+=h/2;i.left+=e[0];i.top+=e[1];return this.each(function(){var f=c(this),k=f.outerWidth(),l=f.outerHeight(),j=c.extend({},i);if(a.my[0]==="right")j.left-=k;else if(a.my[0]==="center")j.left-=k/2;if(a.my[1]==="bottom")j.top-=l;else if(a.my[1]==="center")j.top-=l/2;j.left=parseInt(j.left);j.top=parseInt(j.top);c.each(["left","top"],function(o,r){c.ui.position[d[o]]&&c.ui.position[d[o]][r](j,{targetWidth:g,targetHeight:h,elemWidth:k,
elemHeight:l,offset:e,my:a.my,at:a.at})});c.fn.bgiframe&&f.bgiframe();f.offset(c.extend(j,{using:a.using}))})};c.ui.position={fit:{left:function(a,b){var d=c(window);b=a.left+b.elemWidth-d.width()-d.scrollLeft();a.left=b>0?a.left-b:Math.max(0,a.left)},top:function(a,b){var d=c(window);b=a.top+b.elemHeight-d.height()-d.scrollTop();a.top=b>0?a.top-b:Math.max(0,a.top)}},flip:{left:function(a,b){if(b.at[0]!=="center"){var d=c(window);d=a.left+b.elemWidth-d.width()-d.scrollLeft();var e=b.my[0]==="left"?
-b.elemWidth:b.my[0]==="right"?b.elemWidth:0,g=-2*b.offset[0];a.left+=a.left<0?e+b.targetWidth+g:d>0?e-b.targetWidth+g:0}},top:function(a,b){if(b.at[1]!=="center"){var d=c(window);d=a.top+b.elemHeight-d.height()-d.scrollTop();var e=b.my[1]==="top"?-b.elemHeight:b.my[1]==="bottom"?b.elemHeight:0,g=b.at[1]==="top"?b.targetHeight:-b.targetHeight,h=-2*b.offset[1];a.top+=a.top<0?e+b.targetHeight+h:d>0?e+g+h:0}}}};if(!c.offset.setOffset){c.offset.setOffset=function(a,b){if(/static/.test(c.curCSS(a,"position")))a.style.position=
"relative";var d=c(a),e=d.offset(),g=parseInt(c.curCSS(a,"top",true),10)||0,h=parseInt(c.curCSS(a,"left",true),10)||0;e={top:b.top-e.top+g,left:b.left-e.left+h};"using"in b?b.using.call(a,e):d.css(e)};c.fn.offset=function(a){var b=this[0];if(!b||!b.ownerDocument)return null;if(a)return this.each(function(){c.offset.setOffset(this,a)});return q.call(this)}}})(jQuery);
(function(b){b.widget("ui.progressbar",{options:{value:0},_create:function(){this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this._valueMin(),"aria-valuemax":this._valueMax(),"aria-valuenow":this._value()});this.valueDiv=b("<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>").appendTo(this.element);this._refreshValue()},destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow");
this.valueDiv.remove();b.Widget.prototype.destroy.apply(this,arguments)},value:function(a){if(a===undefined)return this._value();this._setOption("value",a);return this},_setOption:function(a,c){switch(a){case "value":this.options.value=c;this._refreshValue();this._trigger("change");break}b.Widget.prototype._setOption.apply(this,arguments)},_value:function(){var a=this.options.value;if(typeof a!=="number")a=0;if(a<this._valueMin())a=this._valueMin();if(a>this._valueMax())a=this._valueMax();return a},
_valueMin:function(){return 0},_valueMax:function(){return 100},_refreshValue:function(){var a=this.value();this.valueDiv[a===this._valueMax()?"addClass":"removeClass"]("ui-corner-right").width(a+"%");this.element.attr("aria-valuenow",a)}});b.extend(b.ui.progressbar,{version:"1.8.1"})})(jQuery);
(function(d){d.widget("ui.slider",d.ui.mouse,{widgetEventPrefix:"slide",options:{animate:false,distance:0,max:100,min:0,orientation:"horizontal",range:false,step:1,value:0,values:null},_create:function(){var b=this,a=this.options;this._mouseSliding=this._keySliding=false;this._animateOff=true;this._handleIndex=null;this._detectOrientation();this._mouseInit();this.element.addClass("ui-slider ui-slider-"+this.orientation+" ui-widget ui-widget-content ui-corner-all");a.disabled&&this.element.addClass("ui-slider-disabled ui-disabled");
this.range=d([]);if(a.range){if(a.range===true){this.range=d("<div></div>");if(!a.values)a.values=[this._valueMin(),this._valueMin()];if(a.values.length&&a.values.length!==2)a.values=[a.values[0],a.values[0]]}else this.range=d("<div></div>");this.range.appendTo(this.element).addClass("ui-slider-range");if(a.range==="min"||a.range==="max")this.range.addClass("ui-slider-range-"+a.range);this.range.addClass("ui-widget-header")}d(".ui-slider-handle",this.element).length===0&&d("<a href='#'></a>").appendTo(this.element).addClass("ui-slider-handle");
if(a.values&&a.values.length)for(;d(".ui-slider-handle",this.element).length<a.values.length;)d("<a href='#'></a>").appendTo(this.element).addClass("ui-slider-handle");this.handles=d(".ui-slider-handle",this.element).addClass("ui-state-default ui-corner-all");this.handle=this.handles.eq(0);this.handles.add(this.range).filter("a").click(function(c){c.preventDefault()}).hover(function(){a.disabled||d(this).addClass("ui-state-hover")},function(){d(this).removeClass("ui-state-hover")}).focus(function(){if(a.disabled)d(this).blur();
else{d(".ui-slider .ui-state-focus").removeClass("ui-state-focus");d(this).addClass("ui-state-focus")}}).blur(function(){d(this).removeClass("ui-state-focus")});this.handles.each(function(c){d(this).data("index.ui-slider-handle",c)});this.handles.keydown(function(c){var e=true,f=d(this).data("index.ui-slider-handle"),g,h,i;if(!b.options.disabled){switch(c.keyCode){case d.ui.keyCode.HOME:case d.ui.keyCode.END:case d.ui.keyCode.PAGE_UP:case d.ui.keyCode.PAGE_DOWN:case d.ui.keyCode.UP:case d.ui.keyCode.RIGHT:case d.ui.keyCode.DOWN:case d.ui.keyCode.LEFT:e=
false;if(!b._keySliding){b._keySliding=true;d(this).addClass("ui-state-active");g=b._start(c,f);if(g===false)return}break}i=b.options.step;g=b.options.values&&b.options.values.length?(h=b.values(f)):(h=b.value());switch(c.keyCode){case d.ui.keyCode.HOME:h=b._valueMin();break;case d.ui.keyCode.END:h=b._valueMax();break;case d.ui.keyCode.PAGE_UP:h=g+(b._valueMax()-b._valueMin())/5;break;case d.ui.keyCode.PAGE_DOWN:h=g-(b._valueMax()-b._valueMin())/5;break;case d.ui.keyCode.UP:case d.ui.keyCode.RIGHT:if(g===
b._valueMax())return;h=g+i;break;case d.ui.keyCode.DOWN:case d.ui.keyCode.LEFT:if(g===b._valueMin())return;h=g-i;break}b._slide(c,f,h);return e}}).keyup(function(c){var e=d(this).data("index.ui-slider-handle");if(b._keySliding){b._keySliding=false;b._stop(c,e);b._change(c,e);d(this).removeClass("ui-state-active")}});this._refreshValue();this._animateOff=false},destroy:function(){this.handles.remove();this.range.remove();this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-slider-disabled ui-widget ui-widget-content ui-corner-all").removeData("slider").unbind(".slider");
this._mouseDestroy();return this},_mouseCapture:function(b){var a=this.options,c,e,f,g,h,i;if(a.disabled)return false;this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()};this.elementOffset=this.element.offset();c={x:b.pageX,y:b.pageY};e=this._normValueFromMouse(c);f=this._valueMax()-this._valueMin()+1;h=this;this.handles.each(function(j){var k=Math.abs(e-h.values(j));if(f>k){f=k;g=d(this);i=j}});if(a.range===true&&this.values(1)===a.min){i+=1;g=d(this.handles[i])}if(this._start(b,
i)===false)return false;this._mouseSliding=true;h._handleIndex=i;g.addClass("ui-state-active").focus();a=g.offset();this._clickOffset=!d(b.target).parents().andSelf().is(".ui-slider-handle")?{left:0,top:0}:{left:b.pageX-a.left-g.width()/2,top:b.pageY-a.top-g.height()/2-(parseInt(g.css("borderTopWidth"),10)||0)-(parseInt(g.css("borderBottomWidth"),10)||0)+(parseInt(g.css("marginTop"),10)||0)};e=this._normValueFromMouse(c);this._slide(b,i,e);return this._animateOff=true},_mouseStart:function(){return true},
_mouseDrag:function(b){var a=this._normValueFromMouse({x:b.pageX,y:b.pageY});this._slide(b,this._handleIndex,a);return false},_mouseStop:function(b){this.handles.removeClass("ui-state-active");this._mouseSliding=false;this._stop(b,this._handleIndex);this._change(b,this._handleIndex);this._clickOffset=this._handleIndex=null;return this._animateOff=false},_detectOrientation:function(){this.orientation=this.options.orientation==="vertical"?"vertical":"horizontal"},_normValueFromMouse:function(b){var a;
if(this.orientation==="horizontal"){a=this.elementSize.width;b=b.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)}else{a=this.elementSize.height;b=b.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)}a=b/a;if(a>1)a=1;if(a<0)a=0;if(this.orientation==="vertical")a=1-a;b=this._valueMax()-this._valueMin();return this._trimAlignValue(this._valueMin()+a*b)},_start:function(b,a){var c={handle:this.handles[a],value:this.value()};if(this.options.values&&this.options.values.length){c.value=
this.values(a);c.values=this.values()}return this._trigger("start",b,c)},_slide:function(b,a,c){var e;if(this.options.values&&this.options.values.length){e=this.values(a?0:1);if(this.options.values.length===2&&this.options.range===true&&(a===0&&c>e||a===1&&c<e))c=e;if(c!==this.values(a)){e=this.values();e[a]=c;b=this._trigger("slide",b,{handle:this.handles[a],value:c,values:e});this.values(a?0:1);b!==false&&this.values(a,c,true)}}else if(c!==this.value()){b=this._trigger("slide",b,{handle:this.handles[a],
value:c});b!==false&&this.value(c)}},_stop:function(b,a){var c={handle:this.handles[a],value:this.value()};if(this.options.values&&this.options.values.length){c.value=this.values(a);c.values=this.values()}this._trigger("stop",b,c)},_change:function(b,a){if(!this._keySliding&&!this._mouseSliding){var c={handle:this.handles[a],value:this.value()};if(this.options.values&&this.options.values.length){c.value=this.values(a);c.values=this.values()}this._trigger("change",b,c)}},value:function(b){if(arguments.length){this.options.value=
this._trimAlignValue(b);this._refreshValue();this._change(null,0)}return this._value()},values:function(b,a){var c,e,f;if(arguments.length>1){this.options.values[b]=this._trimAlignValue(a);this._refreshValue();this._change(null,b)}if(arguments.length)if(d.isArray(arguments[0])){c=this.options.values;e=arguments[0];for(f=0;f<c.length;f+=1){c[f]=this._trimAlignValue(e[f]);this._change(null,f)}this._refreshValue()}else return this.options.values&&this.options.values.length?this._values(b):this.value();
else return this._values()},_setOption:function(b,a){var c,e=0;if(d.isArray(this.options.values))e=this.options.values.length;d.Widget.prototype._setOption.apply(this,arguments);switch(b){case "disabled":if(a){this.handles.filter(".ui-state-focus").blur();this.handles.removeClass("ui-state-hover");this.handles.attr("disabled","disabled");this.element.addClass("ui-disabled")}else{this.handles.removeAttr("disabled");this.element.removeClass("ui-disabled")}break;case "orientation":this._detectOrientation();
this.element.removeClass("ui-slider-horizontal ui-slider-vertical").addClass("ui-slider-"+this.orientation);this._refreshValue();break;case "value":this._animateOff=true;this._refreshValue();this._change(null,0);this._animateOff=false;break;case "values":this._animateOff=true;this._refreshValue();for(c=0;c<e;c+=1)this._change(null,c);this._animateOff=false;break}},_value:function(){var b=this.options.value;return b=this._trimAlignValue(b)},_values:function(b){var a,c;if(arguments.length){a=this.options.values[b];
return a=this._trimAlignValue(a)}else{a=this.options.values.slice();for(c=0;c<a.length;c+=1)a[c]=this._trimAlignValue(a[c]);return a}},_trimAlignValue:function(b){if(b<this._valueMin())return this._valueMin();if(b>this._valueMax())return this._valueMax();var a=this.options.step,c=b%a;b=b-c;if(c>=a/2)b+=a;return parseFloat(b.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},_refreshValue:function(){var b=this.options.range,a=this.options,c=this,
e=!this._animateOff?a.animate:false,f,g={},h,i,j,k;if(this.options.values&&this.options.values.length)this.handles.each(function(l){f=(c.values(l)-c._valueMin())/(c._valueMax()-c._valueMin())*100;g[c.orientation==="horizontal"?"left":"bottom"]=f+"%";d(this).stop(1,1)[e?"animate":"css"](g,a.animate);if(c.options.range===true)if(c.orientation==="horizontal"){if(l===0)c.range.stop(1,1)[e?"animate":"css"]({left:f+"%"},a.animate);if(l===1)c.range[e?"animate":"css"]({width:f-h+"%"},{queue:false,duration:a.animate})}else{if(l===
0)c.range.stop(1,1)[e?"animate":"css"]({bottom:f+"%"},a.animate);if(l===1)c.range[e?"animate":"css"]({height:f-h+"%"},{queue:false,duration:a.animate})}h=f});else{i=this.value();j=this._valueMin();k=this._valueMax();f=k!==j?(i-j)/(k-j)*100:0;g[c.orientation==="horizontal"?"left":"bottom"]=f+"%";this.handle.stop(1,1)[e?"animate":"css"](g,a.animate);if(b==="min"&&this.orientation==="horizontal")this.range.stop(1,1)[e?"animate":"css"]({width:f+"%"},a.animate);if(b==="max"&&this.orientation==="horizontal")this.range[e?
"animate":"css"]({width:100-f+"%"},{queue:false,duration:a.animate});if(b==="min"&&this.orientation==="vertical")this.range.stop(1,1)[e?"animate":"css"]({height:f+"%"},a.animate);if(b==="max"&&this.orientation==="vertical")this.range[e?"animate":"css"]({height:100-f+"%"},{queue:false,duration:a.animate})}}});d.extend(d.ui.slider,{version:"1.8.1"})})(jQuery);
(function(d){var s=0,u=0;d.widget("ui.tabs",{options:{add:null,ajaxOptions:null,cache:false,cookie:null,collapsible:false,disable:null,disabled:[],enable:null,event:"click",fx:null,idPrefix:"ui-tabs-",load:null,panelTemplate:"<div></div>",remove:null,select:null,show:null,spinner:"<em>Loading&#8230;</em>",tabTemplate:'<li><a href="#{href}"><span>#{label}</span></a></li>'},_create:function(){this._tabify(true)},_setOption:function(c,e){if(c=="selected")this.options.collapsible&&e==this.options.selected||
this.select(e);else{this.options[c]=e;this._tabify()}},_tabId:function(c){return c.title&&c.title.replace(/\s/g,"_").replace(/[^A-Za-z0-9\-_:\.]/g,"")||this.options.idPrefix+ ++s},_sanitizeSelector:function(c){return c.replace(/:/g,"\\:")},_cookie:function(){var c=this.cookie||(this.cookie=this.options.cookie.name||"ui-tabs-"+ ++u);return d.cookie.apply(null,[c].concat(d.makeArray(arguments)))},_ui:function(c,e){return{tab:c,panel:e,index:this.anchors.index(c)}},_cleanup:function(){this.lis.filter(".ui-state-processing").removeClass("ui-state-processing").find("span:data(label.tabs)").each(function(){var c=
d(this);c.html(c.data("label.tabs")).removeData("label.tabs")})},_tabify:function(c){function e(g,f){g.css({display:""});!d.support.opacity&&f.opacity&&g[0].style.removeAttribute("filter")}this.list=this.element.find("ol,ul").eq(0);this.lis=d("li:has(a[href])",this.list);this.anchors=this.lis.map(function(){return d("a",this)[0]});this.panels=d([]);var a=this,b=this.options,h=/^#.+/;this.anchors.each(function(g,f){var j=d(f).attr("href"),l=j.split("#")[0],p;if(l&&(l===location.toString().split("#")[0]||
(p=d("base")[0])&&l===p.href)){j=f.hash;f.href=j}if(h.test(j))a.panels=a.panels.add(a._sanitizeSelector(j));else if(j!="#"){d.data(f,"href.tabs",j);d.data(f,"load.tabs",j.replace(/#.*$/,""));j=a._tabId(f);f.href="#"+j;f=d("#"+j);if(!f.length){f=d(b.panelTemplate).attr("id",j).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").insertAfter(a.panels[g-1]||a.list);f.data("destroy.tabs",true)}a.panels=a.panels.add(f)}else b.disabled.push(g)});if(c){this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all");
this.list.addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.lis.addClass("ui-state-default ui-corner-top");this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom");if(b.selected===undefined){location.hash&&this.anchors.each(function(g,f){if(f.hash==location.hash){b.selected=g;return false}});if(typeof b.selected!="number"&&b.cookie)b.selected=parseInt(a._cookie(),10);if(typeof b.selected!="number"&&this.lis.filter(".ui-tabs-selected").length)b.selected=
this.lis.index(this.lis.filter(".ui-tabs-selected"));b.selected=b.selected||(this.lis.length?0:-1)}else if(b.selected===null)b.selected=-1;b.selected=b.selected>=0&&this.anchors[b.selected]||b.selected<0?b.selected:0;b.disabled=d.unique(b.disabled.concat(d.map(this.lis.filter(".ui-state-disabled"),function(g){return a.lis.index(g)}))).sort();d.inArray(b.selected,b.disabled)!=-1&&b.disabled.splice(d.inArray(b.selected,b.disabled),1);this.panels.addClass("ui-tabs-hide");this.lis.removeClass("ui-tabs-selected ui-state-active");
if(b.selected>=0&&this.anchors.length){this.panels.eq(b.selected).removeClass("ui-tabs-hide");this.lis.eq(b.selected).addClass("ui-tabs-selected ui-state-active");a.element.queue("tabs",function(){a._trigger("show",null,a._ui(a.anchors[b.selected],a.panels[b.selected]))});this.load(b.selected)}d(window).bind("unload",function(){a.lis.add(a.anchors).unbind(".tabs");a.lis=a.anchors=a.panels=null})}else b.selected=this.lis.index(this.lis.filter(".ui-tabs-selected"));this.element[b.collapsible?"addClass":
"removeClass"]("ui-tabs-collapsible");b.cookie&&this._cookie(b.selected,b.cookie);c=0;for(var i;i=this.lis[c];c++)d(i)[d.inArray(c,b.disabled)!=-1&&!d(i).hasClass("ui-tabs-selected")?"addClass":"removeClass"]("ui-state-disabled");b.cache===false&&this.anchors.removeData("cache.tabs");this.lis.add(this.anchors).unbind(".tabs");if(b.event!="mouseover"){var k=function(g,f){f.is(":not(.ui-state-disabled)")&&f.addClass("ui-state-"+g)},n=function(g,f){f.removeClass("ui-state-"+g)};this.lis.bind("mouseover.tabs",
function(){k("hover",d(this))});this.lis.bind("mouseout.tabs",function(){n("hover",d(this))});this.anchors.bind("focus.tabs",function(){k("focus",d(this).closest("li"))});this.anchors.bind("blur.tabs",function(){n("focus",d(this).closest("li"))})}var m,o;if(b.fx)if(d.isArray(b.fx)){m=b.fx[0];o=b.fx[1]}else m=o=b.fx;var q=o?function(g,f){d(g).closest("li").addClass("ui-tabs-selected ui-state-active");f.hide().removeClass("ui-tabs-hide").animate(o,o.duration||"normal",function(){e(f,o);a._trigger("show",
null,a._ui(g,f[0]))})}:function(g,f){d(g).closest("li").addClass("ui-tabs-selected ui-state-active");f.removeClass("ui-tabs-hide");a._trigger("show",null,a._ui(g,f[0]))},r=m?function(g,f){f.animate(m,m.duration||"normal",function(){a.lis.removeClass("ui-tabs-selected ui-state-active");f.addClass("ui-tabs-hide");e(f,m);a.element.dequeue("tabs")})}:function(g,f){a.lis.removeClass("ui-tabs-selected ui-state-active");f.addClass("ui-tabs-hide");a.element.dequeue("tabs")};this.anchors.bind(b.event+".tabs",
function(){var g=this,f=d(this).closest("li"),j=a.panels.filter(":not(.ui-tabs-hide)"),l=d(a._sanitizeSelector(this.hash));if(f.hasClass("ui-tabs-selected")&&!b.collapsible||f.hasClass("ui-state-disabled")||f.hasClass("ui-state-processing")||a._trigger("select",null,a._ui(this,l[0]))===false){this.blur();return false}b.selected=a.anchors.index(this);a.abort();if(b.collapsible)if(f.hasClass("ui-tabs-selected")){b.selected=-1;b.cookie&&a._cookie(b.selected,b.cookie);a.element.queue("tabs",function(){r(g,
j)}).dequeue("tabs");this.blur();return false}else if(!j.length){b.cookie&&a._cookie(b.selected,b.cookie);a.element.queue("tabs",function(){q(g,l)});a.load(a.anchors.index(this));this.blur();return false}b.cookie&&a._cookie(b.selected,b.cookie);if(l.length){j.length&&a.element.queue("tabs",function(){r(g,j)});a.element.queue("tabs",function(){q(g,l)});a.load(a.anchors.index(this))}else throw"jQuery UI Tabs: Mismatching fragment identifier.";d.browser.msie&&this.blur()});this.anchors.bind("click.tabs",
function(){return false})},destroy:function(){var c=this.options;this.abort();this.element.unbind(".tabs").removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible").removeData("tabs");this.list.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.anchors.each(function(){var e=d.data(this,"href.tabs");if(e)this.href=e;var a=d(this).unbind(".tabs");d.each(["href","load","cache"],function(b,h){a.removeData(h+".tabs")})});this.lis.unbind(".tabs").add(this.panels).each(function(){d.data(this,
"destroy.tabs")?d(this).remove():d(this).removeClass("ui-state-default ui-corner-top ui-tabs-selected ui-state-active ui-state-hover ui-state-focus ui-state-disabled ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide")});c.cookie&&this._cookie(null,c.cookie);return this},add:function(c,e,a){if(a===undefined)a=this.anchors.length;var b=this,h=this.options;e=d(h.tabTemplate.replace(/#\{href\}/g,c).replace(/#\{label\}/g,e));c=!c.indexOf("#")?c.replace("#",""):this._tabId(d("a",e)[0]);e.addClass("ui-state-default ui-corner-top").data("destroy.tabs",
true);var i=d("#"+c);i.length||(i=d(h.panelTemplate).attr("id",c).data("destroy.tabs",true));i.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide");if(a>=this.lis.length){e.appendTo(this.list);i.appendTo(this.list[0].parentNode)}else{e.insertBefore(this.lis[a]);i.insertBefore(this.panels[a])}h.disabled=d.map(h.disabled,function(k){return k>=a?++k:k});this._tabify();if(this.anchors.length==1){h.selected=0;e.addClass("ui-tabs-selected ui-state-active");i.removeClass("ui-tabs-hide");
this.element.queue("tabs",function(){b._trigger("show",null,b._ui(b.anchors[0],b.panels[0]))});this.load(0)}this._trigger("add",null,this._ui(this.anchors[a],this.panels[a]));return this},remove:function(c){var e=this.options,a=this.lis.eq(c).remove(),b=this.panels.eq(c).remove();if(a.hasClass("ui-tabs-selected")&&this.anchors.length>1)this.select(c+(c+1<this.anchors.length?1:-1));e.disabled=d.map(d.grep(e.disabled,function(h){return h!=c}),function(h){return h>=c?--h:h});this._tabify();this._trigger("remove",
null,this._ui(a.find("a")[0],b[0]));return this},enable:function(c){var e=this.options;if(d.inArray(c,e.disabled)!=-1){this.lis.eq(c).removeClass("ui-state-disabled");e.disabled=d.grep(e.disabled,function(a){return a!=c});this._trigger("enable",null,this._ui(this.anchors[c],this.panels[c]));return this}},disable:function(c){var e=this.options;if(c!=e.selected){this.lis.eq(c).addClass("ui-state-disabled");e.disabled.push(c);e.disabled.sort();this._trigger("disable",null,this._ui(this.anchors[c],this.panels[c]))}return this},
select:function(c){if(typeof c=="string")c=this.anchors.index(this.anchors.filter("[href$="+c+"]"));else if(c===null)c=-1;if(c==-1&&this.options.collapsible)c=this.options.selected;this.anchors.eq(c).trigger(this.options.event+".tabs");return this},load:function(c){var e=this,a=this.options,b=this.anchors.eq(c)[0],h=d.data(b,"load.tabs");this.abort();if(!h||this.element.queue("tabs").length!==0&&d.data(b,"cache.tabs"))this.element.dequeue("tabs");else{this.lis.eq(c).addClass("ui-state-processing");
if(a.spinner){var i=d("span",b);i.data("label.tabs",i.html()).html(a.spinner)}this.xhr=d.ajax(d.extend({},a.ajaxOptions,{url:h,success:function(k,n){d(e._sanitizeSelector(b.hash)).html(k);e._cleanup();a.cache&&d.data(b,"cache.tabs",true);e._trigger("load",null,e._ui(e.anchors[c],e.panels[c]));try{a.ajaxOptions.success(k,n)}catch(m){}},error:function(k,n){e._cleanup();e._trigger("load",null,e._ui(e.anchors[c],e.panels[c]));try{a.ajaxOptions.error(k,n,c,b)}catch(m){}}}));e.element.dequeue("tabs");return this}},
abort:function(){this.element.queue([]);this.panels.stop(false,true);this.element.queue("tabs",this.element.queue("tabs").splice(-2,2));if(this.xhr){this.xhr.abort();delete this.xhr}this._cleanup();return this},url:function(c,e){this.anchors.eq(c).removeData("cache.tabs").data("load.tabs",e);return this},length:function(){return this.anchors.length}});d.extend(d.ui.tabs,{version:"1.8.1"});d.extend(d.ui.tabs.prototype,{rotation:null,rotate:function(c,e){var a=this,b=this.options,h=a._rotate||(a._rotate=
function(i){clearTimeout(a.rotation);a.rotation=setTimeout(function(){var k=b.selected;a.select(++k<a.anchors.length?k:0)},c);i&&i.stopPropagation()});e=a._unrotate||(a._unrotate=!e?function(i){i.clientX&&a.rotate(null)}:function(){t=b.selected;h()});if(c){this.element.bind("tabsshow",h);this.anchors.bind(b.event+".tabs",e);h()}else{clearTimeout(a.rotation);this.element.unbind("tabsshow",h);this.anchors.unbind(b.event+".tabs",e);delete this._rotate;delete this._unrotate}return this}})})(jQuery);

/*
 * jQuery JSON Plugin
 * version: 2.1 (2009-08-14)
 *
 * This document is licensed as free software under the terms of the
 * MIT License: http://www.opensource.org/licenses/mit-license.php
 *
 * Brantley Harris wrote this plugin. It is based somewhat on the JSON.org 
 * website's http://www.json.org/json2.js, which proclaims:
 * "NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.", a sentiment that
 * I uphold.
 *
 * It is also influenced heavily by MochiKit's serializeJSON, which is 
 * copyrighted 2005 by Bob Ippolito.
 */
 
(function($) {
    /** jQuery.toJSON( json-serializble )
        Converts the given argument into a JSON respresentation.

        If an object has a "toJSON" function, that will be used to get the representation.
        Non-integer/string keys are skipped in the object, as are keys that point to a function.

        json-serializble:
            The *thing* to be converted.
     **/
    $.toJSON = function(o)
    {
        if (typeof(JSON) == 'object' && JSON.stringify)
            return JSON.stringify(o);
        
        var type = typeof(o);
    
        if (o === null)
            return "null";
    
        if (type == "undefined")
            return undefined;
        
        if (type == "number" || type == "boolean")
            return o + "";
    
        if (type == "string")
            return $.quoteString(o);
    
        if (type == 'object')
        {
            if (typeof o.toJSON == "function") 
                return $.toJSON( o.toJSON() );
            
            if (o.constructor === Date)
            {
                var month = o.getUTCMonth() + 1;
                if (month < 10) month = '0' + month;

                var day = o.getUTCDate();
                if (day < 10) day = '0' + day;

                var year = o.getUTCFullYear();
                
                var hours = o.getUTCHours();
                if (hours < 10) hours = '0' + hours;
                
                var minutes = o.getUTCMinutes();
                if (minutes < 10) minutes = '0' + minutes;
                
                var seconds = o.getUTCSeconds();
                if (seconds < 10) seconds = '0' + seconds;
                
                var milli = o.getUTCMilliseconds();
                if (milli < 100) milli = '0' + milli;
                if (milli < 10) milli = '0' + milli;

                return '"' + year + '-' + month + '-' + day + 'T' +
                             hours + ':' + minutes + ':' + seconds + 
                             '.' + milli + 'Z"'; 
            }

            if (o.constructor === Array) 
            {
                var ret = [];
                for (var i = 0; i < o.length; i++)
                    ret.push( $.toJSON(o[i]) || "null" );

                return "[" + ret.join(",") + "]";
            }
        
            var pairs = [];
            for (var k in o) {
                var name;
                var type = typeof k;

                if (type == "number")
                    name = '"' + k + '"';
                else if (type == "string")
                    name = $.quoteString(k);
                else
                    continue;  //skip non-string or number keys
            
                if (typeof o[k] == "function") 
                    continue;  //skip pairs where the value is a function.
            
                var val = $.toJSON(o[k]);
            
                pairs.push(name + ":" + val);
            }

            return "{" + pairs.join(", ") + "}";
        }
    };

    /** jQuery.evalJSON(src)
        Evaluates a given piece of json source.
     **/
    $.evalJSON = function(src)
    {
        if (typeof(JSON) == 'object' && JSON.parse)
            return JSON.parse(src);
        return eval("(" + src + ")");
    };
    
    /** jQuery.secureEvalJSON(src)
        Evals JSON in a way that is *more* secure.
    **/
    $.secureEvalJSON = function(src)
    {
        if (typeof(JSON) == 'object' && JSON.parse)
            return JSON.parse(src);
        
        var filtered = src;
        filtered = filtered.replace(/\\["\\\/bfnrtu]/g, '@');
        filtered = filtered.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']');
        filtered = filtered.replace(/(?:^|:|,)(?:\s*\[)+/g, '');
        
        if (/^[\],:{}\s]*$/.test(filtered))
            return eval("(" + src + ")");
        else
            throw new SyntaxError("Error parsing JSON, source is not valid.");
    };

    /** jQuery.quoteString(string)
        Returns a string-repr of a string, escaping quotes intelligently.  
        Mostly a support function for toJSON.
    
        Examples:
            >>> jQuery.quoteString("apple")
            "apple"
        
            >>> jQuery.quoteString('"Where are we going?", she asked.')
            "\"Where are we going?\", she asked."
     **/
    $.quoteString = function(string)
    {
        if (string.match(_escapeable))
        {
            return '"' + string.replace(_escapeable, function (a) 
            {
                var c = _meta[a];
                if (typeof c === 'string') return c;
                c = a.charCodeAt();
                return '\\u00' + Math.floor(c / 16).toString(16) + (c % 16).toString(16);
            }) + '"';
        }
        return '"' + string + '"';
    };
    
    var _escapeable = /["\\\x00-\x1f\x7f-\x9f]/g;
    
    var _meta = {
        '\b': '\\b',
        '\t': '\\t',
        '\n': '\\n',
        '\f': '\\f',
        '\r': '\\r',
        '"' : '\\"',
        '\\': '\\\\'
    };
})(jQuery);

/*jslint browser: true */ /*global jQuery: true */

/**
 * jQuery Cookie plugin
 *
 * Copyright (c) 2010 Klaus Hartl (stilbuero.de)
 * Dual licensed under the MIT and GPL licenses:
 * http://www.opensource.org/licenses/mit-license.php
 * http://www.gnu.org/licenses/gpl.html
 *
 */

// TODO JsDoc

/**
 * Create a cookie with the given key and value and other optional parameters.
 *
 * @example $.cookie('the_cookie', 'the_value');
 * @desc Set the value of a cookie.
 * @example $.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'jquery.com', secure: true });
 * @desc Create a cookie with all available options.
 * @example $.cookie('the_cookie', 'the_value');
 * @desc Create a session cookie.
 * @example $.cookie('the_cookie', null);
 * @desc Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain
 *       used when the cookie was set.
 *
 * @param String key The key of the cookie.
 * @param String value The value of the cookie.
 * @param Object options An object literal containing key/value pairs to provide optional cookie attributes.
 * @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object.
 *                             If a negative value is specified (e.g. a date in the past), the cookie will be deleted.
 *                             If set to null or omitted, the cookie will be a session cookie and will not be retained
 *                             when the the browser exits.
 * @option String path The value of the path atribute of the cookie (default: path of page that created the cookie).
 * @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie).
 * @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will
 *                        require a secure protocol (like HTTPS).
 * @type undefined
 *
 * @name $.cookie
 * @cat Plugins/Cookie
 * @author Klaus Hartl/klaus.hartl@stilbuero.de
 */

/**
 * Get the value of a cookie with the given key.
 *
 * @example $.cookie('the_cookie');
 * @desc Get the value of a cookie.
 *
 * @param String key The key of the cookie.
 * @return The value of the cookie.
 * @type String
 *
 * @name $.cookie
 * @cat Plugins/Cookie
 * @author Klaus Hartl/klaus.hartl@stilbuero.de
 */
jQuery.cookie = function (key, value, options) {
    
    // key and at least value given, set cookie...
    if (arguments.length > 1 && String(value) !== "[object Object]") {
        options = jQuery.extend({}, options);

        if (value === null || value === undefined) {
            options.expires = -1;
        }

        if (typeof options.expires === 'number') {
            var days = options.expires, t = options.expires = new Date();
            t.setDate(t.getDate() + days);
        }
        
        value = String(value);
        
        return (document.cookie = [
            encodeURIComponent(key), '=',
            options.raw ? value : encodeURIComponent(value),
            options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
            options.path ? '; path=' + options.path : '',
            options.domain ? '; domain=' + options.domain : '',
            options.secure ? '; secure' : ''
        ].join(''));
    }

    // key and possibly options given, get cookie...
    options = value || {};
    var result, decode = options.raw ? function (s) { return s; } : decodeURIComponent;
    return (result = new RegExp('(?:^|; )' + encodeURIComponent(key) + '=([^;]*)').exec(document.cookie)) ? decode(result[1]) : null;
};

/* Simple JavaScript Inheritance
 * By John Resig http://ejohn.org/
 * MIT Licensed.
 */
// Inspired by base2 and Prototype
(function(){
  var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;

  // The base Class implementation (does nothing)
  this.Class = function(){};
 
  // Create a new Class that inherits from this class
  Class.extend = function(prop) {
    var _super = this.prototype;
   
    // Instantiate a base class (but only create the instance,
    // don't run the init constructor)
    initializing = true;
    var prototype = new this();
    initializing = false;
   
    // Copy the properties over onto the new prototype
    for (var name in prop) {
      // Check if we're overwriting an existing function
      prototype[name] = typeof prop[name] == "function" &&
        typeof _super[name] == "function" && fnTest.test(prop[name]) ?
        (function(name, fn){
          return function() {
            var tmp = this._super;
           
            // Add a new ._super() method that is the same method
            // but on the super-class
            this._super = _super[name];
           
            // The method only need to be bound temporarily, so we
            // remove it when we're done executing
            var ret = fn.apply(this, arguments);       
            this._super = tmp;
           
            return ret;
          };
        })(name, prop[name]) :
        prop[name];
    }
    
    Class.implement = function(implementor){
		var impl = new implementor();
		impl.implement(Class);
    	return Class;
    }
   
    // The dummy class constructor
    function Class() {
      // All construction is actually done in the init method
      if ( !initializing && this.init )
        this.init.apply(this, arguments);
    }
   
    // Populate our constructed prototype object
    Class.prototype = prototype;
   
    // Enforce the constructor to be what we expect
    Class.constructor = Class;

    // And make this class extendable
    Class.extend = arguments.callee;
   
    return Class;
  };
})();
//micro template based on John Resg code
function tmpl(tmpl_id,data){
	try {
		if ( typeof tmpl.cache == 'undefined' ) {
			tmpl.cache = new Array();
	    }
		if( tmpl.cache[tmpl_id]!=null ){
			var fn = tmpl.cache[tmpl_id];
			return fn(data);		
		}
		str = document.getElementById(tmpl_id).innerHTML;
		str = str.replace(/\\/g, "@SPC@");
		str = str.replace(/'/g, "&apos;");
		fnStr = "var p=[],print=function(){p.push.apply(p,arguments);};" +
	    
	    // Introduce the data as local variables using with(){}
	    "with(obj){p.push('" +
	    
	    // Convert the template into pure JavaScript
	    str
	      .replace(/[\r\t\n]/g, " ")
	      .split("<%").join("\t")
	      .replace(/((^|%>)[^\t]*)'/g, "$1\r")
	      .replace(/\t=(.*?)%>/g, "',$1,'")
	      .split("\t").join("');")
	      .split("%>").join("p.push('")
	      .split("\r").join("\\'")
	  + "');}return p.join('');";
		fnStr = fnStr.replace(/@SPC@/g, "\\");
		var fn = new Function("obj", fnStr);
		tmpl.cache[tmpl_id] = fn;
		return fn(data);
	} catch (e) {
		log(e+":"+tmpl_id, 'rendering');
	}
}

/*
 Highcharts JS v2.1.7 (2011-10-19)

 (c) 2009-2011 Torstein H?nsi

 License: www.highcharts.com/license
*/
(function(){function E(a,b){var c;a||(a={});for(c in b)a[c]=b[c];return a}function K(a,b){return parseInt(a,b||10)}function Ya(a){return typeof a==="string"}function Ga(a){return typeof a==="object"}function fa(a){return typeof a==="number"}function ib(a){return V.log(a)/V.LN10}function jb(a,b){for(var c=a.length;c--;)if(a[c]===b){a.splice(c,1);break}}function q(a){return a!==ra&&a!==null}function F(a,b,c){var d,e;if(Ya(b))q(c)?a.setAttribute(b,c):a&&a.getAttribute&&(e=a.getAttribute(b));else if(q(b)&&
Ga(b))for(d in b)a.setAttribute(d,b[d]);return e}function tb(a){return Object.prototype.toString.call(a)==="[object Array]"?a:[a]}function n(){var a=arguments,b,c,d=a.length;for(b=0;b<d;b++)if(c=a[b],typeof c!=="undefined"&&c!==null)return c}function C(a,b){if(Hb&&b&&b.opacity!==ra)b.filter="alpha(opacity="+b.opacity*100+")";E(a.style,b)}function W(a,b,c,d,e){a=G.createElement(a);b&&E(a,b);e&&C(a,{padding:0,border:X,margin:0});c&&C(a,c);d&&d.appendChild(a);return a}function ca(a,b){var c=function(){};
c.prototype=new a;E(c.prototype,b);return c}function mc(a,b,c,d){var e=sa.lang,f=isNaN(b=ya(b))?2:b,b=c===void 0?e.decimalPoint:c,d=d===void 0?e.thousandsSep:d,e=a<0?"-":"",c=String(K(a=ya(+a||0).toFixed(f))),g=c.length>3?c.length%3:0;return e+(g?c.substr(0,g)+d:"")+c.substr(g).replace(/(\d{3})(?=\d)/g,"$1"+d)+(f?b+ya(a-c).toFixed(f).slice(2):"")}function nc(a){for(var b={left:a.offsetLeft,top:a.offsetTop},a=a.offsetParent;a;)b.left+=a.offsetLeft,b.top+=a.offsetTop,a!==G.body&&a!==G.documentElement&&
(b.left-=a.scrollLeft,b.top-=a.scrollTop),a=a.offsetParent;return b}function oc(){this.symbol=this.color=0}function zc(a,b,c,d,e,f,g){var h=g.x,g=g.y,i=h-a+c-25,j=g-b+d+10,m;i<7&&(i=c+h+15);i+a>c+e&&(i-=i+a-(c+e),j-=b,m=!0);j<5?(j=5,m&&g>=j&&g<=j+b&&(j=g+b-5)):j+b>d+f&&(j=d+f-b-5);return{x:i,y:j}}function pc(a,b){var c=a.length,d;for(d=0;d<c;d++)a[d].ss_i=d;a.sort(function(a,c){var d=b(a,c);return d===0?a.ss_i-c.ss_i:d});for(d=0;d<c;d++)delete a[d].ss_i}function ub(a){for(var b in a)a[b]&&a[b].destroy&&
a[b].destroy(),delete a[b]}function kb(a,b){vb=n(a,b.animation)}function wb(){var a=sa.global.useUTC;Ib=a?Date.UTC:function(a,c,d,e,f,g){return(new Date(a,c,n(d,1),n(e,0),n(f,0),n(g,0))).getTime()};Wb=a?"getUTCMinutes":"getMinutes";Xb=a?"getUTCHours":"getHours";Yb=a?"getUTCDay":"getDay";xb=a?"getUTCDate":"getDate";Jb=a?"getUTCMonth":"getMonth";Kb=a?"getUTCFullYear":"getFullYear";qc=a?"setUTCMinutes":"setMinutes";rc=a?"setUTCHours":"setHours";Zb=a?"setUTCDate":"setDate";sc=a?"setUTCMonth":"setMonth";
tc=a?"setUTCFullYear":"setFullYear"}function Lb(a){za||(za=W(Za));a&&za.appendChild(a);za.innerHTML=""}function lb(){}function yb(a,b){function c(a){function b(a,c){this.pos=a;this.minor=c;this.isNew=!0;c||this.addLabel()}function c(a){if(a)this.options=a,this.id=a.id;return this}function d(a,b,c,e){this.isNegative=b;this.options=a;this.x=c;this.stack=e;this.alignOptions={align:a.align||(M?b?"left":"right":"center"),verticalAlign:a.verticalAlign||(M?"middle":b?"bottom":"top"),y:n(a.y,M?4:b?14:-6),
x:n(a.x,M?b?-6:6:0)};this.textAlign=a.textAlign||(M?b?"right":"left":"center")}function e(){var a=[],b=[],c;Ca=Ha=null;F=[];l(Y,function(e){c=!1;l(["xAxis","yAxis"],function(a){if(e.isCartesian&&(a==="xAxis"&&p||a==="yAxis"&&!p)&&(e.options[a]===s.index||e.options[a]===ra&&s.index===0))e[a]=ja,F.push(e),c=!0});!e.visible&&o.ignoreHiddenSeries&&(c=!1);if(c){var f,g,h,i,j,k;if(!p){f=e.options.stacking;Tb=f==="percent";if(f)j=e.options.stack,i=e.type+n(j,""),k="-"+i,e.stackKey=i,g=a[i]||[],a[i]=g,h=
b[k]||[],b[k]=h;Tb&&(Ca=0,Ha=99)}e.isCartesian&&(l(e.data,function(a){var b=a.x,c=a.y,e=c<0,m=e?h:g,zb=e?k:i;Ca===null&&(Ca=Ha=a[$]);p?b>Ha?Ha=b:b<Ca&&(Ca=b):q(c)&&(f&&(m[b]=q(m[b])?m[b]+c:c),c=m?m[b]:c,a=n(a.low,c),Tb||(c>Ha?Ha=c:a<Ca&&(Ca=a)),f&&(v[zb]||(v[zb]={}),v[zb][b]||(v[zb][b]=new d(s.stackLabels,e,b,j)),v[zb][b].setTotal(c)))}),/(area|column|bar)/.test(e.type)&&!p&&(Ca>=0?(Ca=0,ia=!0):Ha<0&&(Ha=0,ka=!0)))}})}function f(a,b){var c,d;X=b?1:V.pow(10,Ia(V.log(a)/V.LN10));c=a/X;if(!b&&(b=[1,
2,2.5,5,10],s.allowDecimals===!1||N))X===1?b=[1,2,5,10]:X<=0.1&&(b=[1/X]);for(d=0;d<b.length;d++)if(a=b[d],c<=(b[d]+(b[d+1]||b[d]))/2)break;a*=X;return a}function g(a){var b;b=a;X=n(X,V.pow(10,Ia(V.log(na)/V.LN10)));X<1&&(b=z(1/X)*10,b=z(a*b)/b);return b}function h(){var a,b,c,d,e=s.tickInterval,i=s.tickPixelInterval;a=s.maxZoom||(p&&!q(s.min)&&!q(s.max)?Ka(k.smallestInterval*5,Ha-Ca):null);t=r?T:O;S?(c=k[p?"xAxis":"yAxis"][s.linkedTo],d=c.getExtremes(),J=n(d.min,d.dataMin),L=n(d.max,d.dataMax)):
(J=n(C,s.min,Ca),L=n(Qa,s.max,Ha));N&&(J=ib(J),L=ib(L));L-J<a&&(d=(a-L+J)/2,J=Z(J-d,n(s.min,J-d),Ca),L=Ka(J+a,n(s.max,J+a),Ha));if(!ua&&!Tb&&!S&&q(J)&&q(L)){a=L-J||1;if(!q(s.min)&&!q(C)&&da&&(Ca<0||!ia))J-=a*da;if(!q(s.max)&&!q(Qa)&&ea&&(Ha>0||!ka))L+=a*ea}na=J===L?1:S&&!e&&i===c.options.tickPixelInterval?c.tickInterval:n(e,ua?1:(L-J)*i/t);!Mb&&!q(s.tickInterval)&&(na=f(na));ja.tickInterval=na;pa=s.minorTickInterval==="auto"&&na?na/5:s.minorTickInterval;if(Mb){P=[];var e=sa.global.useUTC,j=1E3/La,
m=6E4/La,ta=36E5/La,i=864E5/La;a=6048E5/La;d=2592E6/La;var Ua=31556952E3/La,v=[["second",j,[1,2,5,10,15,30]],["minute",m,[1,2,5,10,15,30]],["hour",ta,[1,2,3,4,6,8,12]],["day",i,[1,2]],["week",a,[1,2]],["month",d,[1,2,3,4,6]],["year",Ua,null]],w=v[6],l=w[1],u=w[2];for(c=0;c<v.length;c++)if(w=v[c],l=w[1],u=w[2],v[c+1]&&na<=(l*u[u.length-1]+v[c+1][1])/2)break;l===Ua&&na<5*l&&(u=[1,2,5]);v=f(na/l,u);u=new Date(J*La);u.setMilliseconds(0);l>=j&&u.setSeconds(l>=m?0:v*Ia(u.getSeconds()/v));if(l>=m)u[qc](l>=
ta?0:v*Ia(u[Wb]()/v));if(l>=ta)u[rc](l>=i?0:v*Ia(u[Xb]()/v));if(l>=i)u[Zb](l>=d?1:v*Ia(u[xb]()/v));l>=d&&(u[sc](l>=Ua?0:v*Ia(u[Jb]()/v)),b=u[Kb]());l>=Ua&&(b-=b%v,u[tc](b));if(l===a)u[Zb](u[xb]()-u[Yb]()+s.startOfWeek);c=1;b=u[Kb]();j=u.getTime()/La;m=u[Jb]();for(ta=u[xb]();j<L&&c<T;)P.push(j),l===Ua?j=Ib(b+c*v,0)/La:l===d?j=Ib(b,m+c*v)/La:!e&&(l===i||l===a)?j=Ib(b,m,ta+c*v*(l===i?1:7)):j+=l*v,c++;P.push(j);Da=s.dateTimeLabelFormats[w[0]]}else{c=g(Ia(J/na)*na);b=g($b(L/na)*na);P=[];for(c=g(c);c<=
b;)P.push(c),c=g(c+na)}if(!S){if(ua||p&&k.hasColumn){b=(ua?1:na)*0.5;if(ua||!q(n(s.min,C)))J-=b;if(ua||!q(n(s.max,Qa)))L+=b}b=P[0];c=P[P.length-1];s.startOnTick?J=b:J>b&&P.shift();s.endOnTick?L=c:L<c&&P.pop();Va||(Va={x:0,y:0});if(!Mb&&P.length>Va[$])Va[$]=P.length}}function i(){var a,b;U=J;ba=L;e();h();y=Ea;Ea=t/(L-J||1);if(!p)for(a in v)for(b in v[a])v[a][b].cum=v[a][b].total;if(!ja.isDirty)ja.isDirty=J!==U||L!==ba}function j(a){a=(new c(a)).render();W.push(a);return a}function m(){var a=s.title,
d=s.stackLabels,e=s.alternateGridColor,f=s.lineWidth,g,h,i=(g=k.hasRendered)&&q(U)&&!isNaN(U);h=F.length&&q(J)&&q(L);t=r?T:O;Ea=t/(L-J||1);H=r?B:Ma;if(h||S){if(pa&&!ua)for(h=J+(P[0]-J)%pa;h<=L;h+=pa)fa[h]||(fa[h]=new b(h,!0)),i&&fa[h].isNew&&fa[h].render(null,!0),fa[h].isActive=!0,fa[h].render();l(P,function(a,b){if(!S||a>=J&&a<=L)i&&R[a].isNew&&R[a].render(b,!0),R[a].isActive=!0,R[a].render(b)});e&&l(P,function(a,b){if(b%2===0&&a<L)la[a]||(la[a]=new c),la[a].options={from:a,to:P[b+1]!==ra?P[b+1]:
L,color:e},la[a].render(),la[a].isActive=!0});g||l((s.plotLines||[]).concat(s.plotBands||[]),function(a){W.push((new c(a)).render())})}l([R,fa,la],function(a){for(var b in a)a[b].isActive?a[b].isActive=!1:(a[b].destroy(),delete a[b])});f&&(g=B+(u?T:0)+x,h=Aa-Ma-(u?O:0)+x,g=I.crispLine([va,r?B:g,r?h:D,aa,r?wa-ca:g,r?h:Aa-Ma],f),Wa?Wa.animate({d:g}):Wa=I.path(g).attr({stroke:s.lineColor,"stroke-width":f,zIndex:7}).add());if(A)g=r?B:D,f=K(a.style.fontSize||12),g={low:g+(r?0:t),middle:g+t/2,high:g+(r?
t:0)}[a.align],f=(r?D+O:B)+(r?1:-1)*(u?-1:1)*Fa+(Ra===2?f:0),A[A.isNew?"attr":"animate"]({x:r?g:f+(u?T:0)+x+(a.x||0),y:r?f-(u?O:0)+x:g+(a.y||0)}),A.isNew=!1;if(d&&d.enabled){var j,ta,d=ja.stackTotalGroup;if(!d)ja.stackTotalGroup=d=I.g("stack-labels").attr({visibility:Pa,zIndex:6}).translate(B,D).add();for(j in v)for(ta in a=v[j],a)a[ta].render(d)}ja.isDirty=!1}function w(a){for(var b=W.length;b--;)W[b].id===a&&W[b].destroy()}var p=a.isX,u=a.opposite,r=M?!p:p,Ra=r?u?0:2:u?1:3,v={},s=Q(p?Nb:ac,[Ac,
Bc,uc,Cc][Ra],a),ja=this,A,Ab=s.type,Mb=Ab==="datetime",N=Ab==="logarithmic",x=s.offset||0,$=p?"x":"y",t,Ea,y,H=r?B:Ma,mb,nb,ob,G,Wa,Ca,Ha,F,C,Qa,L=null,J=null,U,ba,da=s.minPadding,ea=s.maxPadding,S=q(s.linkedTo),ia,ka,Tb,Ab=s.events,gb,W=[],na,pa,X,P,R={},fa={},la={},qa,xa,Fa,Da,ua=s.categories,Oa=s.labels.formatter||function(){var a=this.value;return Da?Ob(Da,a):na%1E6===0?a/1E6+"M":na%1E3===0?a/1E3+"k":!ua&&a>=1E3?mc(a,0):a},Ga=r&&s.labels.staggerLines,za=s.reversed,Ba=ua&&s.tickmarkPlacement===
"between"?0.5:0;b.prototype={addLabel:function(){var a=this.pos,b=s.labels,c=!(a===J&&!n(s.showFirstLabel,1)||a===L&&!n(s.showLastLabel,0)),d=ua&&r&&ua.length&&!b.step&&!b.staggerLines&&!b.rotation&&T/ua.length||!r&&T/2,e=ua&&q(ua[a])?ua[a]:a,f=this.label,a=Oa.call({isFirst:a===P[0],isLast:a===P[P.length-1],dateTimeLabelFormat:Da,value:N?V.pow(10,e):e}),d=d&&{width:Z(1,z(d-2*(b.padding||10)))+oa},d=E(d,b.style);f===ra?this.label=q(a)&&c&&b.enabled?I.text(a,0,0,b.useHTML).attr({align:b.align,rotation:b.rotation}).css(d).add(ob):
null:f&&f.attr({text:a}).css(d)},getLabelSize:function(){var a=this.label;return a?(this.labelBBox=a.getBBox())[r?"height":"width"]:0},render:function(a,b){var c=!this.minor,d=this.label,e=this.pos,f=s.labels,g=this.gridLine,h=c?s.gridLineWidth:s.minorGridLineWidth,i=c?s.gridLineColor:s.minorGridLineColor,j=c?s.gridLineDashStyle:s.minorGridLineDashStyle,m=this.mark,k=c?s.tickLength:s.minorTickLength,ta=c?s.tickWidth:s.minorTickWidth||0,v=c?s.tickColor:s.minorTickColor,l=c?s.tickPosition:s.minorTickPosition,
Ua=f.step,w=b&&Ta||Aa,p;p=r?mb(e+Ba,null,null,b)+H:B+x+(u?(b&&Sa||wa)-ca-B:0);w=r?w-Ma+x-(u?O:0):w-mb(e+Ba,null,null,b)-H;if(h){e=nb(e+Ba,h,b);if(g===ra){g={stroke:i,"stroke-width":h};if(j)g.dashstyle=j;if(c)g.zIndex=1;this.gridLine=g=h?I.path(e).attr(g).add(G):null}!b&&g&&e&&g.animate({d:e})}if(ta)l==="inside"&&(k=-k),u&&(k=-k),c=I.crispLine([va,p,w,aa,p+(r?0:-k),w+(r?k:0)],ta),m?m.animate({d:c}):this.mark=I.path(c).attr({stroke:v,"stroke-width":ta}).add(ob);if(d&&!isNaN(p)){p=p+f.x-(Ba&&r?Ba*Ea*
(za?-1:1):0);w=w+f.y-(Ba&&!r?Ba*Ea*(za?1:-1):0);q(f.y)||(w+=K(d.styles.lineHeight)*0.9-d.getBBox().height/2);Ga&&(w+=a/(Ua||1)%Ga*16);if(Ua)d[a%Ua?"hide":"show"]();d[this.isNew?"attr":"animate"]({x:p,y:w})}this.isNew=!1},destroy:function(){ub(this)}};c.prototype={render:function(){var a=this,b=a.options,c=b.label,d=a.label,e=b.width,f=b.to,g=b.from,h=b.value,i,j=b.dashStyle,m=a.svgElem,k=[],ta,v,s=b.color;v=b.zIndex;var l=b.events;N&&(g=ib(g),f=ib(f),h=ib(h));if(e){if(k=nb(h,e),b={stroke:s,"stroke-width":e},
j)b.dashstyle=j}else if(q(g)&&q(f))g=Z(g,J),f=Ka(f,L),i=nb(f),(k=nb(g))&&i?k.push(i[4],i[5],i[1],i[2]):k=null,b={fill:s};else return;if(q(v))b.zIndex=v;if(m)k?m.animate({d:k},null,m.onGetPath):(m.hide(),m.onGetPath=function(){m.show()});else if(k&&k.length&&(a.svgElem=m=I.path(k).attr(b).add(),l))for(ta in j=function(b){m.on(b,function(c){l[b].apply(a,[c])})},l)j(ta);if(c&&q(c.text)&&k&&k.length&&T>0&&O>0){c=Q({align:r&&i&&"center",x:r?!i&&4:10,verticalAlign:!r&&i&&"middle",y:r?i?16:10:i?6:-4,rotation:r&&
!i&&90},c);if(!d)a.label=d=I.text(c.text,0,0).attr({align:c.textAlign||c.align,rotation:c.rotation,zIndex:v}).css(c.style).add();i=[k[1],k[4],n(k[6],k[1])];k=[k[2],k[5],n(k[7],k[2])];ta=Ka.apply(V,i);v=Ka.apply(V,k);d.align(c,!1,{x:ta,y:v,width:Z.apply(V,i)-ta,height:Z.apply(V,k)-v});d.show()}else d&&d.hide();return a},destroy:function(){ub(this);jb(W,this)}};d.prototype={destroy:function(){ub(this)},setTotal:function(a){this.cum=this.total=a},render:function(a){var b=this.options.formatter.call(this);
this.label?this.label.attr({text:b,visibility:Ja}):this.label=k.renderer.text(b,0,0).css(this.options.style).attr({align:this.textAlign,rotation:this.options.rotation,visibility:Ja}).add(a)},setOffset:function(a,b){var c=this.isNegative,d=ja.translate(this.total),e=ja.translate(0),e=ya(d-e),f=k.xAxis[0].translate(this.x)+a,g=k.plotHeight,c={x:M?c?d:d-e:f,y:M?g-f-b:c?g-d-e:g-d,width:M?e:b,height:M?b:e};this.label&&this.label.align(this.alignOptions,null,c).attr({visibility:Pa})}};mb=function(a,b,c,
d,e){var f=1,g=0,h=d?y:Ea,d=d?U:J;h||(h=Ea);c&&(f*=-1,g=t);za&&(f*=-1,g-=f*t);b?(za&&(a=t-a),a=a/h+d,N&&e&&(a=V.pow(10,a))):(N&&e&&(a=ib(a)),a=f*(a-d)*h+g);return a};nb=function(a,b,c){var d,e,f,a=mb(a,null,null,c),g=c&&Ta||Aa,h=c&&Sa||wa,i,c=e=z(a+H);d=f=z(g-a-H);if(isNaN(a))i=!0;else if(r){if(d=D,f=g-Ma,c<B||c>B+T)i=!0}else if(c=B,e=h-ca,d<D||d>D+O)i=!0;return i?null:I.crispLine([va,c,d,aa,e,f],b||0)};M&&p&&za===ra&&(za=!0);E(ja,{addPlotBand:j,addPlotLine:j,adjustTickAmount:function(){if(Va&&!Mb&&
!ua&&!S){var a=qa,b=P.length;qa=Va[$];if(b<qa){for(;P.length<qa;)P.push(g(P[P.length-1]+na));Ea*=(b-1)/(qa-1);L=P[P.length-1]}if(q(a)&&qa!==a)ja.isDirty=!0}},categories:ua,getExtremes:function(){return{min:J,max:L,dataMin:Ca,dataMax:Ha,userMin:C,userMax:Qa}},getPlotLinePath:nb,getThreshold:function(a){J>a?a=J:L<a&&(a=L);return mb(a,0,1)},isXAxis:p,options:s,plotLinesAndBands:W,getOffset:function(){var a=F.length&&q(J)&&q(L),c=0,d=0,e=s.title,f=s.labels,g=[-1,1,1,-1][Ra],h;ob||(ob=I.g("axis").attr({zIndex:7}).add(),
G=I.g("grid").attr({zIndex:1}).add());xa=0;if(a||S)l(P,function(a){R[a]?R[a].addLabel():R[a]=new b(a);if(Ra===0||Ra===2||{1:"left",3:"right"}[Ra]===f.align)xa=Z(R[a].getLabelSize(),xa)}),Ga&&(xa+=(Ga-1)*16);else for(h in R)R[h].destroy(),delete R[h];if(e&&e.text){if(!A)A=ja.axisTitle=I.text(e.text,0,0,e.useHTML).attr({zIndex:7,rotation:e.rotation||0,align:e.textAlign||{low:"left",middle:"center",high:"right"}[e.align]}).css(e.style).add(),A.isNew=!0;c=A.getBBox()[r?"height":"width"];d=n(e.margin,
r?5:10)}x=g*(s.offset||ma[Ra]);Fa=xa+(Ra!==2&&xa&&g*s.labels[r?"y":"x"])+d;ma[Ra]=Z(ma[Ra],Fa+c+g*x)},render:m,setCategories:function(b,c){ja.categories=a.categories=ua=b;l(F,function(a){a.translate();a.setTooltipPoints(!0)});ja.isDirty=!0;n(c,!0)&&k.redraw()},setExtremes:function(a,b,c,d){c=n(c,!0);ga(ja,"setExtremes",{min:a,max:b},function(){C=a;Qa=b;c&&k.redraw(d)})},setScale:i,setTickPositions:h,translate:mb,redraw:function(){$a.resetTracker&&$a.resetTracker();m();l(W,function(a){a.render()});
l(F,function(a){a.isDirty=!0})},removePlotBand:w,removePlotLine:w,reversed:za,stacks:v,destroy:function(){var a;Na(ja);for(a in v)ub(v[a]),v[a]=null;if(ja.stackTotalGroup)ja.stackTotalGroup=ja.stackTotalGroup.destroy();l([R,fa,la,W],function(a){ub(a)});l([Wa,ob,G,A],function(a){a&&a.destroy()});Wa=ob=G=A=null}});for(gb in Ab)ha(ja,gb,Ab[gb]);i()}function d(){var b={};return{add:function(c,d,e,f){b[c]||(d=I.text(d,0,0).css(a.toolbar.itemStyle).align({align:"right",x:-ca-20,y:D+30}).on("click",f).attr({align:"right",
zIndex:20}).add(),b[c]=d)},remove:function(a){Lb(b[a].element);b[a]=null}}}function e(a){function b(){var a=this.points||tb(this),c=a[0].series.xAxis,d=this.x,c=c&&c.options.type==="datetime",e=Ya(d)||c,f;f=e?['<span style="font-size: 10px">'+(c?Ob("%A, %b %e, %Y",d):d)+"</span>"]:[];l(a,function(a){f.push(a.point.tooltipFormatter(e))});return f.join("<br/>")}function c(a,b){o=u?a:(2*o+a)/3;v=u?b:(v+b)/2;s.translate(o,v);bc=ya(a-o)>1||ya(b-v)>1?function(){c(a,b)}:null}function d(){if(!u){var a=k.hoverPoints;
s.hide();l(h,function(a){a&&a.hide()});a&&l(a,function(a){a.setState()});k.hoverPoints=null;u=!0}}var e,f=a.borderWidth,g=a.crosshairs,h=[],i=a.style,j=a.shared,m=K(i.padding),w=f+m,u=!0,p,r,o=0,v=0;i.padding=0;var s=I.g("tooltip").attr({zIndex:8}).add(),n=I.rect(w,w,0,0,a.borderRadius,f).attr({fill:a.backgroundColor,"stroke-width":f}).add(s).shadow(a.shadow),A=I.text("",m+w,K(i.fontSize)+m+w,a.useHTML).attr({zIndex:1}).css(i).add(s);s.hide();return{shared:j,refresh:function(f){var i,v,o,N=0,q={},
t=[];o=f.tooltipPos;i=a.formatter||b;q=k.hoverPoints;j?(q&&l(q,function(a){a.setState()}),k.hoverPoints=f,l(f,function(a){a.setState(xa);N+=a.plotY;t.push(a.getLabelConfig())}),v=f[0].plotX,N=z(N)/f.length,q={x:f[0].category},q.points=t,f=f[0]):q=f.getLabelConfig();q=i.call(q);e=f.series;v=j?v:f.plotX;N=j?N:f.plotY;i=z(o?o[0]:M?T-N:v);v=z(o?o[1]:M?O-v:N);o=j||!f.series.isCartesian||db(i,v);q===!1||!o?d():(u&&(s.show(),u=!1),A.attr({text:q}),o=A.getBBox(),p=o.width+2*m,r=o.height+2*m,n.attr({width:p,
height:r,stroke:a.borderColor||f.color||e.color||"#606060"}),i=zc(p,r,B,D,T,O,{x:i,y:v}),c(z(i.x-w),z(i.y-w)));if(g){g=tb(g);for(i=g.length;i--;)if(v=f.series[i?"yAxis":"xAxis"],g[i]&&v)if(v=v.getPlotLinePath(f[i?"y":"x"],1),h[i])h[i].attr({d:v,visibility:Pa});else{o={"stroke-width":g[i].width||1,stroke:g[i].color||"#C0C0C0",zIndex:2};if(g[i].dashStyle)o.dashstyle=g[i].dashStyle;h[i]=I.path(v).attr(o).add()}}},hide:d,destroy:function(){l(h,function(a){a&&a.destroy()});l([n,A,s],function(a){a&&a.destroy()});
n=A=s=null}}}function f(a){function b(a){var c,d=vc&&G.width/G.body.scrollWidth-1,e,f,g,a=a||ka.event;if(!a.target)a.target=a.srcElement;c=a.touches?a.touches.item(0):a;if(a.type!=="mousemove"||ka.opera||d)Da=nc(H),e=Da.left,f=Da.top;Hb?(g=a.x,c=a.y):c.layerX===ra?(g=c.pageX-e,c=c.pageY-f):(g=a.layerX,c=a.layerY);d&&(g+=z((d+1)*e-e),c+=z((d+1)*f-f));return E(a,{chartX:g,chartY:c})}function c(a){var b={xAxis:[],yAxis:[]};l(da,function(c){var d=c.translate,e=c.isXAxis;b[e?"xAxis":"yAxis"].push({axis:c,
value:d((M?!e:e)?a.chartX-B:O-a.chartY+D,!0)})});return b}function d(){var a=k.hoverSeries,b=k.hoverPoint;if(b)b.onMouseOut();if(a)a.onMouseOut();eb&&eb.hide();cc=null}function f(){if(m){var a={xAxis:[],yAxis:[]},b=m.getBBox(),c=b.x-B,d=b.y-D;j&&(l(da,function(e){var f=e.translate,g=e.isXAxis,h=M?!g:g,i=f(h?c:O-d-b.height,!0,0,0,1),f=f(h?c+b.width:O-d,!0,0,0,1);a[g?"xAxis":"yAxis"].push({axis:e,min:Ka(i,f),max:Z(i,f)})}),ga(k,"selection",a,dc));m=m.destroy()}k.mouseIsDown=ec=j=!1;Na(G,Oa?"touchend":
"mouseup",f)}function g(a){var b=q(a.pageX)?a.pageX:a.page.x,a=q(a.pageX)?a.pageY:a.page.y;Da&&!db(b-Da.left-B,a-Da.top-D)&&d()}var h,i,j,m,w=o.zoomType,u=/x/.test(w),p=/y/.test(w),r=u&&!M||p&&M,n=p&&!M||u&&M;Pb=function(){Bb?(Bb.translate(B,D),M&&Bb.attr({width:k.plotWidth,height:k.plotHeight}).invert()):k.trackerGroup=Bb=I.g("tracker").attr({zIndex:9}).add()};Pb();if(a.enabled)k.tooltip=eb=e(a);(function(){H.onmousedown=function(a){a=b(a);!Oa&&a.preventDefault&&a.preventDefault();k.mouseIsDown=
ec=!0;h=a.chartX;i=a.chartY;ha(G,Oa?"touchend":"mouseup",f)};var e=function(c){if(!c||!(c.touches&&c.touches.length>1)){c=b(c);if(!Oa)c.returnValue=!1;var d=c.chartX,e=c.chartY,f=!db(d-B,e-D);Da||(Da=nc(H));Oa&&c.type==="touchstart"&&(F(c.target,"isTracker")?k.runTrackerClick||c.preventDefault():!lb&&!f&&c.preventDefault());f&&(d<B?d=B:d>B+T&&(d=B+T),e<D?e=D:e>D+O&&(e=D+O));if(ec&&c.type!=="touchstart"){if(j=Math.sqrt(Math.pow(h-d,2)+Math.pow(i-e,2)),j>10){if(pb&&(u||p)&&db(h-B,i-D))m||(m=I.rect(B,
D,r?1:T,n?1:O,0).attr({fill:o.selectionMarkerFill||"rgba(69,114,167,0.25)",zIndex:7}).add());m&&r&&(d-=h,m.attr({width:ya(d),x:(d>0?0:d)+h}));m&&n&&(e-=i,m.attr({height:ya(e),y:(e>0?0:e)+i}))}}else if(!f){var g,e=k.hoverPoint,d=k.hoverSeries,l,w,A=wa,q=M?c.chartY:c.chartX-B;if(eb&&a.shared){g=[];l=Y.length;for(w=0;w<l;w++)if(Y[w].visible&&Y[w].tooltipPoints.length)c=Y[w].tooltipPoints[q],c._dist=ya(q-c.plotX),A=Ka(A,c._dist),g.push(c);for(l=g.length;l--;)g[l]._dist>A&&g.splice(l,1);if(g.length&&g[0].plotX!==
cc)eb.refresh(g),cc=g[0].plotX}if(d&&d.tracker&&(c=d.tooltipPoints[q])&&c!==e)c.onMouseOver()}return f||!pb}};H.onmousemove=e;ha(H,"mouseleave",d);ha(G,"mousemove",g);H.ontouchstart=function(a){if(u||p)H.onmousedown(a);e(a)};H.ontouchmove=e;H.ontouchend=function(){j&&d()};H.onclick=function(a){var d=k.hoverPoint,a=b(a);a.cancelBubble=!0;if(!j)if(d&&F(a.target,"isTracker")){var e=d.plotX,f=d.plotY;E(d,{pageX:Da.left+B+(M?T-f:e),pageY:Da.top+D+(M?O-e:f)});ga(d.series,"click",E(a,{point:d}));d.firePointEvent("click",
a)}else E(a,c(a)),db(a.chartX-B,a.chartY-D)&&ga(k,"click",a);j=!1}})();yb=setInterval(function(){bc&&bc()},32);E(this,{zoomX:u,zoomY:p,resetTracker:d,destroy:function(){if(k.trackerGroup)k.trackerGroup=Bb=k.trackerGroup.destroy();Na(G,"mousemove",g);H.onclick=H.onmousedown=H.onmousemove=H.ontouchstart=H.ontouchend=H.ontouchmove=null}})}function g(a){var b=a.type||o.type||o.defaultSeriesType,c=la[b],d=k.hasRendered;if(d)if(M&&b==="column")c=la.bar;else if(!M&&b==="bar")c=la.column;b=new c;b.init(k,
a);!d&&b.inverted&&(M=!0);if(b.isCartesian)pb=b.isCartesian;Y.push(b);return b}function h(){o.alignTicks!==!1&&l(da,function(a){a.adjustTickAmount()});Va=null}function i(a){var b=k.isDirtyLegend,c,d=k.isDirtyBox,e=Y.length,f=e,g=k.clipRect;for(kb(a,k);f--;)if(a=Y[f],a.isDirty&&a.options.stacking){c=!0;break}if(c)for(f=e;f--;)if(a=Y[f],a.options.stacking)a.isDirty=!0;l(Y,function(a){a.isDirty&&(a.cleanData(),a.getSegments(),a.options.legendType==="point"&&(b=!0))});if(b&&Cb.renderLegend)Cb.renderLegend(),
k.isDirtyLegend=!1;pb&&(Qb||(Va=null,l(da,function(a){a.setScale()})),h(),Db(),l(da,function(a){if(a.isDirty||d)a.redraw(),d=!0}));d&&(fc(),Pb(),g&&(Eb(g),g.animate({width:k.plotSizeX,height:k.plotSizeY})));l(Y,function(a){a.isDirty&&a.visible&&(!a.isCartesian||a.xAxis)&&a.redraw()});$a&&$a.resetTracker&&$a.resetTracker();ga(k,"redraw")}function j(){var b=a.xAxis||{},d=a.yAxis||{},e,b=tb(b);l(b,function(a,b){a.index=b;a.isX=!0});d=tb(d);l(d,function(a,b){a.index=b});da=b.concat(d);k.xAxis=[];k.yAxis=
[];da=qb(da,function(a){e=new c(a);k[e.isXAxis?"xAxis":"yAxis"].push(e);return e});h()}function m(b,c){ba=Q(a.title,b);ia=Q(a.subtitle,c);l([["title",b,ba],["subtitle",c,ia]],function(a){var b=a[0],c=k[b],d=a[1],a=a[2];c&&d&&(c=c.destroy());a&&a.text&&!c&&(k[b]=I.text(a.text,0,0,a.useHTML).attr({align:a.align,"class":"highcharts-"+b,zIndex:1}).css(a.style).add().align(a,!1,ea))})}function w(){R=o.renderTo;Fa=rb+gc++;Ya(R)&&(R=G.getElementById(R));R.innerHTML="";R.offsetWidth||(U=R.cloneNode(0),C(U,
{position:fb,top:"-9999px",display:""}),G.body.appendChild(U));qa=(U||R).offsetWidth;fa=(U||R).offsetHeight;k.chartWidth=wa=o.width||qa||600;k.chartHeight=Aa=o.height||(fa>19?fa:400);k.container=H=W(Za,{className:"highcharts-container"+(o.className?" "+o.className:""),id:Fa},E({position:wc,overflow:Ja,width:wa+oa,height:Aa+oa,textAlign:"left"},o.style),U||R);k.renderer=I=o.forExport?new Rb(H,wa,Aa,!0):new Sb(H,wa,Aa);var a,b;xc&&H.getBoundingClientRect&&(a=function(){C(H,{left:0,top:0});b=H.getBoundingClientRect();
C(H,{left:-(b.left-K(b.left))+oa,top:-(b.top-K(b.top))+oa})},a(),ha(ka,"resize",a),ha(k,"destroy",function(){Na(ka,"resize",a)}))}function N(){function a(){var c=o.width||R.offsetWidth,d=o.height||R.offsetHeight;if(c&&d){if(c!==qa||d!==fa)clearTimeout(b),b=setTimeout(function(){hc(c,d,!1)},100);qa=c;fa=d}}var b;ha(ka,"resize",a);ha(k,"destroy",function(){Na(ka,"resize",a)})}function x(){ga(k,"endResize",null,function(){Qb-=1})}function t(){var b=a.labels,c=a.credits,e;m();Cb=k.legend=new Vb;Db();
l(da,function(a){a.setTickPositions(!0)});h();Db();fc();pb&&l(da,function(a){a.render()});if(!k.seriesGroup)k.seriesGroup=I.g("series-group").attr({zIndex:3}).add();l(Y,function(a){a.translate();a.setTooltipPoints();a.render()});b.items&&l(b.items,function(){var a=E(b.style,this.style),c=K(a.left)+B,d=K(a.top)+D+12;delete a.left;delete a.top;I.text(this.html,c,d).attr({zIndex:2}).css(a).add()});if(!k.toolbar)k.toolbar=d();if(c.enabled&&!k.credits)e=c.href,k.credits=I.text(c.text,0,0).on("click",function(){if(e)location.href=
e}).attr({align:c.position.align,zIndex:8}).css(c.style).add().align(c.position);Pb();k.hasRendered=!0;U&&(R.appendChild(H),Lb(U))}function r(){var a,b=H&&H.parentNode;if(k!==null){ga(k,"destroy");Na(ka,"unload",r);Na(k);for(a=da.length;a--;)da[a]=da[a].destroy();for(a=Y.length;a--;)Y[a]=Y[a].destroy();l("title,subtitle,seriesGroup,clipRect,credits,tracker".split(","),function(a){var b=k[a];b&&(k[a]=b.destroy())});l([sb,Cb,eb,I,$a],function(a){a&&a.destroy&&a.destroy()});sb=Cb=eb=I=$a=null;if(H)H.innerHTML=
"",Na(H),b&&b.removeChild(H),H=null;clearInterval(yb);for(a in k)delete k[a];k=null}}function $(){!Fb&&ka==ka.top&&G.readyState!=="complete"?G.attachEvent("onreadystatechange",function(){G.detachEvent("onreadystatechange",$);G.readyState==="complete"&&$()}):(w(),ic(),jc(),l(a.series||[],function(a){g(a)}),k.inverted=M=n(M,a.chart.inverted),j(),k.render=t,k.tracker=$a=new f(a.tooltip),t(),ga(k,"load"),b&&b.apply(k,[k]),l(k.callbacks,function(a){a.apply(k,[k])}))}Nb=Q(Nb,sa.xAxis);ac=Q(ac,sa.yAxis);
sa.xAxis=sa.yAxis=null;var a=Q(sa,a),o=a.chart,A=o.margin,A=Ga(A)?A:[A,A,A,A],p=n(o.marginTop,A[0]),u=n(o.marginRight,A[1]),Ea=n(o.marginBottom,A[2]),y=n(o.marginLeft,A[3]),Qa=o.spacingTop,Wa=o.spacingRight,gb=o.spacingBottom,S=o.spacingLeft,ea,ba,ia,D,ca,Ma,B,ma,R,U,H,Fa,qa,fa,wa,Aa,Sa,Ta,sb,Ba,Xa,za,k=this,lb=(A=o.events)&&!!A.click,cb,db,eb,ec,hb,wb,kc,O,T,$a,Bb,Pb,Cb,ab,bb,Da,pb=o.showAxes,Qb=0,da=[],Va,Y=[],M,I,bc,yb,cc,fc,Db,ic,jc,hc,dc,Gb,Vb=function(){function a(b,c){var d=b.legendItem,e=
b.legendLine,g=b.legendSymbol,h=p.color,i=c?f.itemStyle.color:h,j=c?b.color:h,h=c?b.pointAttr[pa]:{stroke:h,fill:h};d&&d.css({fill:i});e&&e.attr({stroke:j});g&&g.attr(h)}function b(a,c,d){var e=a.legendItem,f=a.legendLine,g=a.legendSymbol,a=a.checkbox;e&&e.attr({x:c,y:d});f&&f.translate(c,d-4);g&&g.attr({x:c+g.xOff,y:d+g.yOff});if(a)a.x=c,a.y=d}function c(){l(j,function(a){var b=a.checkbox,c=$.alignAttr;b&&C(b,{left:c.translateX+a.legendItemWidth+b.x-40+oa,top:c.translateY+b.y-11+oa})})}function d(c){var e,
j,m,k,l=c.legendItem;k=c.series||c;var o=k.options,t=o&&o.borderWidth||0;if(!l){k=/^(bar|pie|area|column)$/.test(k.type);c.legendItem=l=I.text(f.labelFormatter.call(c),0,0).css(c.visible?w:p).on("mouseover",function(){c.setState(xa);l.css(u)}).on("mouseout",function(){l.css(c.visible?w:p);c.setState()}).on("click",function(){var a=function(){c.setVisible()};c.firePointEvent?c.firePointEvent("legendItemClick",null,a):ga(c,"legendItemClick",null,a)}).attr({zIndex:2}).add($);if(!k&&o&&o.lineWidth){var x=
{"stroke-width":o.lineWidth,zIndex:2};if(o.dashStyle)x.dashstyle=o.dashStyle;c.legendLine=I.path([va,-h-i,0,aa,-i,0]).attr(x).add($)}k?e=I.rect(j=-h-i,m=-11,h,12,2).attr({zIndex:3}).add($):o&&o.marker&&o.marker.enabled&&(e=I.symbol(c.symbol,j=-h/2-i,m=-4,o.marker.radius).attr({zIndex:3}).add($));if(e)e.xOff=j+t%2/2,e.yOff=m+t%2/2;c.legendSymbol=e;a(c,c.visible);if(o&&o.showCheckbox)c.checkbox=W("input",{type:"checkbox",checked:c.selected,defaultChecked:c.selected},f.itemCheckboxStyle,H),ha(c.checkbox,
"click",function(a){ga(c,"checkboxClick",{checked:a.target.checked},function(){c.select()})})}e=l.getBBox();j=c.legendItemWidth=f.itemWidth||h+i+e.width+r;N=e.height;if(g&&s-n+j>(B||wa-2*r-n))s=n,A+=N;q=A;b(c,s,A);g?s+=j:A+=N;z=B||Z(g?s-n:j,z)}function e(){s=n;A=o;q=z=0;$||($=I.g("legend").attr({zIndex:7}).add());j=[];l(y,function(a){var b=a.options;b.showInLegend&&(j=j.concat(b.legendType==="point"?a.data:a))});pc(j,function(a,b){return(a.options.legendIndex||0)-(b.options.legendIndex||0)});D&&j.reverse();
l(j,d);ab=B||z;bb=q-o+N;if(x||Ea){ab+=2*r;bb+=2*r;if(t){if(ab>0&&bb>0)t[t.isNew?"attr":"animate"](t.crisp(null,null,null,ab,bb)),t.isNew=!1}else t=I.rect(0,0,ab,bb,f.borderRadius,x||0).attr({stroke:f.borderColor,"stroke-width":x||0,fill:Ea||X}).add($).shadow(f.shadow),t.isNew=!0;t[j.length?"show":"hide"]()}for(var a=["left","right","top","bottom"],b,g=4;g--;)b=a[g],m[b]&&m[b]!=="auto"&&(f[g<2?"align":"verticalAlign"]=b,f[g<2?"x":"y"]=K(m[b])*(g%2?-1:1));j.length&&$.align(E(f,{width:ab,height:bb}),
!0,ea);Qb||c()}var f=k.options.legend;if(f.enabled){var g=f.layout==="horizontal",h=f.symbolWidth,i=f.symbolPadding,j,m=f.style,w=f.itemStyle,u=f.itemHoverStyle,p=f.itemHiddenStyle,r=K(m.padding),o=18,n=4+r+h+i,s,A,q,N=0,t,x=f.borderWidth,Ea=f.backgroundColor,$,z,B=f.width,y=k.series,D=f.reversed;e();ha(k,"endResize",c);return{colorizeItem:a,destroyItem:function(a){var b=a.checkbox;l(["legendItem","legendLine","legendSymbol"],function(b){a[b]&&a[b].destroy()});b&&Lb(a.checkbox)},renderLegend:e,destroy:function(){t&&
(t=t.destroy());$&&($=$.destroy())}}}};db=function(a,b){return a>=0&&a<=T&&b>=0&&b<=O};Gb=function(){ga(k,"selection",{resetSelection:!0},dc);k.toolbar.remove("zoom")};dc=function(a){var b=sa.lang,c=k.pointCount<100;k.toolbar.add("zoom",b.resetZoom,b.resetZoomTitle,Gb);!a||a.resetSelection?l(da,function(a){a.setExtremes(null,null,!1,c)}):l(a.xAxis.concat(a.yAxis),function(a){var b=a.axis;k.tracker[b.isXAxis?"zoomX":"zoomY"]&&b.setExtremes(a.min,a.max,!1,c)});i()};Db=function(){var b=a.legend,c=n(b.margin,
10),d=b.x,e=b.y,f=b.align,g=b.verticalAlign,h;ic();if((k.title||k.subtitle)&&!q(p))(h=Z(k.title&&!ba.floating&&!ba.verticalAlign&&ba.y||0,k.subtitle&&!ia.floating&&!ia.verticalAlign&&ia.y||0))&&(D=Z(D,h+n(ba.margin,15)+Qa));b.enabled&&!b.floating&&(f==="right"?q(u)||(ca=Z(ca,ab-d+c+Wa)):f==="left"?q(y)||(B=Z(B,ab+d+c+S)):g==="top"?q(p)||(D=Z(D,bb+e+c+Qa)):g==="bottom"&&(q(Ea)||(Ma=Z(Ma,bb-e+c+gb))));pb&&l(da,function(a){a.getOffset()});q(y)||(B+=ma[3]);q(p)||(D+=ma[0]);q(Ea)||(Ma+=ma[2]);q(u)||(ca+=
ma[1]);jc()};hc=function(a,b,c){var d=k.title,e=k.subtitle;Qb+=1;kb(c,k);Ta=Aa;Sa=wa;k.chartWidth=wa=z(a);k.chartHeight=Aa=z(b);C(H,{width:wa+oa,height:Aa+oa});I.setSize(wa,Aa,c);T=wa-B-ca;O=Aa-D-Ma;Va=null;l(da,function(a){a.isDirty=!0;a.setScale()});l(Y,function(a){a.isDirty=!0});k.isDirtyLegend=!0;k.isDirtyBox=!0;Db();d&&d.align(null,null,ea);e&&e.align(null,null,ea);i(c);Ta=null;ga(k,"resize");vb===!1?x():setTimeout(x,vb&&vb.duration||500)};jc=function(){k.plotLeft=B=z(B);k.plotTop=D=z(D);k.plotWidth=
T=z(wa-B-ca);k.plotHeight=O=z(Aa-D-Ma);k.plotSizeX=M?O:T;k.plotSizeY=M?T:O;ea={x:S,y:Qa,width:wa-S-Wa,height:Aa-Qa-gb}};ic=function(){D=n(p,Qa);ca=n(u,Wa);Ma=n(Ea,gb);B=n(y,S);ma=[0,0,0,0]};fc=function(){var a=o.borderWidth||0,b=o.backgroundColor,c=o.plotBackgroundColor,d=o.plotBackgroundImage,e,f={x:B,y:D,width:T,height:O};e=a+(o.shadow?8:0);if(a||b)sb?sb.animate(sb.crisp(null,null,null,wa-e,Aa-e)):sb=I.rect(e/2,e/2,wa-e,Aa-e,o.borderRadius,a).attr({stroke:o.borderColor,"stroke-width":a,fill:b||
X}).add().shadow(o.shadow);c&&(Ba?Ba.animate(f):Ba=I.rect(B,D,T,O,0).attr({fill:c}).add().shadow(o.plotShadow));d&&(Xa?Xa.animate(f):Xa=I.image(d,B,D,T,O).add());o.plotBorderWidth&&(za?za.animate(za.crisp(null,B,D,T,O)):za=I.rect(B,D,T,O,0,o.plotBorderWidth).attr({stroke:o.plotBorderColor,"stroke-width":o.plotBorderWidth,zIndex:4}).add());k.isDirtyBox=!1};ha(ka,"unload",r);o.reflow!==!1&&ha(k,"load",N);if(A)for(cb in A)ha(k,cb,A[cb]);k.options=a;k.series=Y;k.addSeries=function(a,b,c){var d;a&&(kb(c,
k),b=n(b,!0),ga(k,"addSeries",{options:a},function(){d=g(a);d.isDirty=!0;k.isDirtyLegend=!0;b&&k.redraw()}));return d};k.animation=n(o.animation,!0);k.destroy=r;k.get=function(a){var b,c,d;for(b=0;b<da.length;b++)if(da[b].options.id===a)return da[b];for(b=0;b<Y.length;b++)if(Y[b].options.id===a)return Y[b];for(b=0;b<Y.length;b++){d=Y[b].data;for(c=0;c<d.length;c++)if(d[c].id===a)return d[c]}return null};k.getSelectedPoints=function(){var a=[];l(Y,function(b){a=a.concat(lc(b.data,function(a){return a.selected}))});
return a};k.getSelectedSeries=function(){return lc(Y,function(a){return a.selected})};k.hideLoading=function(){Ub(hb,{opacity:0},{duration:a.loading.hideDuration,complete:function(){C(hb,{display:X})}});kc=!1};k.isInsidePlot=db;k.redraw=i;k.setSize=hc;k.setTitle=m;k.showLoading=function(b){var c=a.loading;hb||(hb=W(Za,{className:"highcharts-loading"},E(c.style,{left:B+oa,top:D+oa,width:T+oa,height:O+oa,zIndex:10,display:X}),H),wb=W("span",null,c.labelStyle,hb));wb.innerHTML=b||a.lang.loading;kc||
(C(hb,{opacity:0,display:""}),Ub(hb,{opacity:c.style.opacity},{duration:c.showDuration}),kc=!0)};k.pointCount=0;k.counters=new oc;$()}var G=document,ka=window,V=Math,z=V.round,Ia=V.floor,$b=V.ceil,Z=V.max,Ka=V.min,ya=V.abs,S=V.cos,ma=V.sin,qa=V.PI,Gb=qa*2/360,Sa=navigator.userAgent,Hb=/msie/i.test(Sa)&&!ka.opera,Ta=G.documentMode===8,vc=/AppleWebKit/.test(Sa),xc=/Firefox/.test(Sa),Fb=!!G.createElementNS&&!!G.createElementNS("http://www.w3.org/2000/svg","svg").createSVGRect,Dc=xc&&parseInt(Sa.split("Firefox/")[1],
10)<4,Sb,Oa=G.documentElement.ontouchstart!==void 0,Vb={},gc=0,La=1,za,sa,Ob,vb,Ba,ra,Za="div",fb="absolute",wc="relative",Ja="hidden",rb="highcharts-",Pa="visible",oa="px",X="none",va="M",aa="L",yc="rgba(192,192,192,"+(Fb?1.0E-6:0.0020)+")",pa="",xa="hover",Ib,Wb,Xb,Yb,xb,Jb,Kb,qc,rc,Zb,sc,tc,y=ka.HighchartsAdapter,U=y||{},l=U.each,lc=U.grep,qb=U.map,Q=U.merge,ha=U.addEvent,Na=U.removeEvent,ga=U.fireEvent,Ub=U.animate,Eb=U.stop,la={};Ob=function(a,b,c){function d(a){return a.toString().replace(/^([0-9])$/,
"0$1")}if(!q(b)||isNaN(b))return"Invalid date";var a=n(a,"%Y-%m-%d %H:%M:%S"),b=new Date(b*La),e,f=b[Xb](),g=b[Yb](),h=b[xb](),i=b[Jb](),j=b[Kb](),m=sa.lang,l=m.weekdays,b={a:l[g].substr(0,3),A:l[g],d:d(h),e:h,b:m.shortMonths[i],B:m.months[i],m:d(i+1),y:j.toString().substr(2,2),Y:j,H:d(f),I:d(f%12||12),l:f%12||12,M:d(b[Wb]()),p:f<12?"AM":"PM",P:f<12?"am":"pm",S:d(b.getSeconds())};for(e in b)a=a.replace("%"+e,b[e]);return c?a.substr(0,1).toUpperCase()+a.substr(1):a};oc.prototype={wrapColor:function(a){if(this.color>=
a)this.color=0},wrapSymbol:function(a){if(this.symbol>=a)this.symbol=0}};Ba={init:function(a,b,c){var b=b||"",d=a.shift,e=b.indexOf("C")>-1,f=e?7:3,g,b=b.split(" "),c=[].concat(c),h,i,j=function(a){for(g=a.length;g--;)a[g]===va&&a.splice(g+1,0,a[g+1],a[g+2],a[g+1],a[g+2])};e&&(j(b),j(c));a.isArea&&(h=b.splice(b.length-6,6),i=c.splice(c.length-6,6));if(d)c=[].concat(c).splice(0,f).concat(c),a.shift=!1;if(b.length)for(a=c.length;b.length<a;)d=[].concat(b).splice(b.length-f,f),e&&(d[f-6]=d[f-2],d[f-
5]=d[f-1]),b=b.concat(d);h&&(b=b.concat(h),c=c.concat(i));return[b,c]},step:function(a,b,c,d){var e=[],f=a.length;if(c===1)e=d;else if(f===b.length&&c<1)for(;f--;)d=parseFloat(a[f]),e[f]=isNaN(d)?a[f]:c*parseFloat(b[f]-d)+d;else e=b;return e}};y&&y.init&&y.init(Ba);if(!y&&ka.jQuery){var ea=jQuery,l=function(a,b){for(var c=0,d=a.length;c<d;c++)if(b.call(a[c],a[c],c,a)===!1)return c},lc=ea.grep,qb=function(a,b){for(var c=[],d=0,e=a.length;d<e;d++)c[d]=b.call(a[d],a[d],d,a);return c},Q=function(){var a=
arguments;return ea.extend(!0,null,a[0],a[1],a[2],a[3])},ha=function(a,b,c){ea(a).bind(b,c)},Na=function(a,b,c){var d=G.removeEventListener?"removeEventListener":"detachEvent";G[d]&&!a[d]&&(a[d]=function(){});ea(a).unbind(b,c)},ga=function(a,b,c,d){var e=ea.Event(b),f="detached"+b;E(e,c);a[b]&&(a[f]=a[b],a[b]=null);ea(a).trigger(e);a[f]&&(a[b]=a[f],a[f]=null);d&&!e.isDefaultPrevented()&&d(e)},Ub=function(a,b,c){var d=ea(a);if(b.d)a.toD=b.d,b.d=1;d.stop();d.animate(b,c)},Eb=function(a){ea(a).stop()};
ea.extend(ea.easing,{easeOutQuad:function(a,b,c,d,e){return-d*(b/=e)*(b-2)+c}});var Ec=jQuery.fx.step._default,Fc=jQuery.fx.prototype.cur;ea.fx.step._default=function(a){var b=a.elem;b.attr?b.attr(a.prop,a.now):Ec.apply(this,arguments)};ea.fx.step.d=function(a){var b=a.elem;if(!a.started){var c=Ba.init(b,b.d,b.toD);a.start=c[0];a.end=c[1];a.started=!0}b.attr("d",Ba.step(a.start,a.end,a.pos,b.toD))};ea.fx.prototype.cur=function(){var a=this.elem;return a.attr?a.attr(this.prop):Fc.apply(this,arguments)}}y=
{enabled:!0,align:"center",x:0,y:15,style:{color:"#666",fontSize:"11px",lineHeight:"14px"}};sa={colors:"#4572A7,#AA4643,#89A54E,#80699B,#3D96AE,#DB843D,#92A8CD,#A47D7C,#B5CA92".split(","),symbols:["circle","diamond","square","triangle","triangle-down"],lang:{loading:"Loading...",months:"January,February,March,April,May,June,July,August,September,October,November,December".split(","),shortMonths:"Jan,Feb,Mar,Apr,May,June,Jul,Aug,Sep,Oct,Nov,Dec".split(","),weekdays:"Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday".split(","),
decimalPoint:".",resetZoom:"Reset zoom",resetZoomTitle:"Reset zoom level 1:1",thousandsSep:","},global:{useUTC:!0},chart:{borderColor:"#4572A7",borderRadius:5,defaultSeriesType:"line",ignoreHiddenSeries:!0,spacingTop:10,spacingRight:10,spacingBottom:15,spacingLeft:10,style:{fontFamily:'"Lucida Grande", "Lucida Sans Unicode", Verdana, Arial, Helvetica, sans-serif',fontSize:"12px"},backgroundColor:"#FFFFFF",plotBorderColor:"#C0C0C0"},title:{text:"Chart title",align:"center",y:15,style:{color:"#3E576F",
fontSize:"16px"}},subtitle:{text:"",align:"center",y:30,style:{color:"#6D869F"}},plotOptions:{line:{allowPointSelect:!1,showCheckbox:!1,animation:{duration:1E3},events:{},lineWidth:2,shadow:!0,marker:{enabled:!0,lineWidth:0,radius:4,lineColor:"#FFFFFF",states:{hover:{},select:{fillColor:"#FFFFFF",lineColor:"#000000",lineWidth:2}}},point:{events:{}},dataLabels:Q(y,{enabled:!1,y:-6,formatter:function(){return this.y}}),showInLegend:!0,states:{hover:{marker:{}},select:{marker:{}}},stickyTracking:!0}},
labels:{style:{position:fb,color:"#3E576F"}},legend:{enabled:!0,align:"center",layout:"horizontal",labelFormatter:function(){return this.name},borderWidth:1,borderColor:"#909090",borderRadius:5,shadow:!1,style:{padding:"5px"},itemStyle:{cursor:"pointer",color:"#3E576F"},itemHoverStyle:{cursor:"pointer",color:"#000000"},itemHiddenStyle:{color:"#C0C0C0"},itemCheckboxStyle:{position:fb,width:"13px",height:"13px"},symbolWidth:16,symbolPadding:5,verticalAlign:"bottom",x:0,y:0},loading:{hideDuration:100,
labelStyle:{fontWeight:"bold",position:wc,top:"1em"},showDuration:100,style:{position:fb,backgroundColor:"white",opacity:0.5,textAlign:"center"}},tooltip:{enabled:!0,backgroundColor:"rgba(255, 255, 255, .85)",borderWidth:2,borderRadius:5,shadow:!0,snap:Oa?25:10,style:{color:"#333333",fontSize:"12px",padding:"5px",whiteSpace:"nowrap"}},toolbar:{itemStyle:{color:"#4572A7",cursor:"pointer"}},credits:{enabled:!0,text:"Highcharts.com",href:"http://www.highcharts.com",position:{align:"right",x:-10,verticalAlign:"bottom",
y:-5},style:{cursor:"pointer",color:"#909090",fontSize:"10px"}}};var Nb={dateTimeLabelFormats:{second:"%H:%M:%S",minute:"%H:%M",hour:"%H:%M",day:"%e. %b",week:"%e. %b",month:"%b '%y",year:"%Y"},endOnTick:!1,gridLineColor:"#C0C0C0",labels:y,lineColor:"#C0D0E0",lineWidth:1,max:null,min:null,minPadding:0.01,maxPadding:0.01,minorGridLineColor:"#E0E0E0",minorGridLineWidth:1,minorTickColor:"#A0A0A0",minorTickLength:2,minorTickPosition:"outside",startOfWeek:1,startOnTick:!1,tickColor:"#C0D0E0",tickLength:5,
tickmarkPlacement:"between",tickPixelInterval:100,tickPosition:"outside",tickWidth:1,title:{align:"middle",style:{color:"#6D869F",fontWeight:"bold"}},type:"linear"},ac=Q(Nb,{endOnTick:!0,gridLineWidth:1,tickPixelInterval:72,showLastLabel:!0,labels:{align:"right",x:-8,y:3},lineWidth:0,maxPadding:0.05,minPadding:0.05,startOnTick:!0,tickWidth:0,title:{rotation:270,text:"Y-values"},stackLabels:{enabled:!1,formatter:function(){return this.total},style:y.style}}),Cc={labels:{align:"right",x:-8,y:null},
title:{rotation:270}},Bc={labels:{align:"left",x:8,y:null},title:{rotation:90}},uc={labels:{align:"center",x:0,y:14},title:{rotation:0}},Ac=Q(uc,{labels:{y:-5}}),ia=sa.plotOptions,y=ia.line;ia.spline=Q(y);ia.scatter=Q(y,{lineWidth:0,states:{hover:{lineWidth:0}}});ia.area=Q(y,{});ia.areaspline=Q(ia.area);ia.column=Q(y,{borderColor:"#FFFFFF",borderWidth:1,borderRadius:0,groupPadding:0.2,marker:null,pointPadding:0.1,minPointLength:0,states:{hover:{brightness:0.1,shadow:!1},select:{color:"#C0C0C0",borderColor:"#000000",
shadow:!1}},dataLabels:{y:null,verticalAlign:null}});ia.bar=Q(ia.column,{dataLabels:{align:"left",x:5,y:0}});ia.pie=Q(y,{borderColor:"#FFFFFF",borderWidth:1,center:["50%","50%"],colorByPoint:!0,dataLabels:{distance:30,enabled:!0,formatter:function(){return this.point.name},y:5},legendType:"point",marker:null,size:"75%",showInLegend:!1,slicedOffset:10,states:{hover:{brightness:0.1,shadow:!1}}});wb();var Fa=function(a){var b=[],c;(function(a){(c=/rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]?(?:\.[0-9]+)?)\s*\)/.exec(a))?
b=[K(c[1]),K(c[2]),K(c[3]),parseFloat(c[4],10)]:(c=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(a))&&(b=[K(c[1],16),K(c[2],16),K(c[3],16),1])})(a);return{get:function(c){return b&&!isNaN(b[0])?c==="rgb"?"rgb("+b[0]+","+b[1]+","+b[2]+")":c==="a"?b[3]:"rgba("+b.join(",")+")":a},brighten:function(a){if(fa(a)&&a!==0){var c;for(c=0;c<3;c++)b[c]+=K(a*255),b[c]<0&&(b[c]=0),b[c]>255&&(b[c]=255)}return this},setOpacity:function(a){b[3]=a;return this}}};lb.prototype={init:function(a,b){this.element=
G.createElementNS("http://www.w3.org/2000/svg",b);this.renderer=a},animate:function(a,b,c){if(b=n(b,vb,!0)){b=Q(b);if(c)b.complete=c;Ub(this,a,b)}else this.attr(a),c&&c()},attr:function(a,b){var c,d,e,f,g=this.element,h=g.nodeName,i=this.renderer,j,m=this.shadows,l=this.htmlNode,n,x=this;Ya(a)&&q(b)&&(c=a,a={},a[c]=b);if(Ya(a))c=a,h==="circle"?c={x:"cx",y:"cy"}[c]||c:c==="strokeWidth"&&(c="stroke-width"),x=F(g,c)||this[c]||0,c!=="d"&&c!=="visibility"&&(x=parseFloat(x));else for(c in a){j=!1;d=a[c];
if(c==="d")d&&d.join&&(d=d.join(" ")),/(NaN| {2}|^$)/.test(d)&&(d="M 0 0"),this.d=d;else if(c==="x"&&h==="text"){for(e=0;e<g.childNodes.length;e++)f=g.childNodes[e],F(f,"x")===F(g,"x")&&F(f,"x",d);this.rotation&&F(g,"transform","rotate("+this.rotation+" "+d+" "+K(a.y||F(g,"y"))+")")}else if(c==="fill")d=i.color(d,g,c);else if(h==="circle"&&(c==="x"||c==="y"))c={x:"cx",y:"cy"}[c]||c;else if(c==="translateX"||c==="translateY"||c==="rotation"||c==="verticalAlign")this[c]=d,this.updateTransform(),j=!0;
else if(c==="stroke")d=i.color(d,g,c);else if(c==="dashstyle")if(c="stroke-dasharray",d=d&&d.toLowerCase(),d==="solid")d=X;else{if(d){d=d.replace("shortdashdotdot","3,1,1,1,1,1,").replace("shortdashdot","3,1,1,1").replace("shortdot","1,1,").replace("shortdash","3,1,").replace("longdash","8,3,").replace(/dot/g,"1,3,").replace("dash","4,3,").replace(/,$/,"").split(",");for(e=d.length;e--;)d[e]=K(d[e])*a["stroke-width"];d=d.join(",")}}else c==="isTracker"?this[c]=d:c==="width"?d=K(d):c==="align"?(c=
"text-anchor",d={left:"start",center:"middle",right:"end"}[d]):c==="title"&&(e=G.createElementNS("http://www.w3.org/2000/svg","title"),e.appendChild(G.createTextNode(d)),g.appendChild(e));c==="strokeWidth"&&(c="stroke-width");vc&&c==="stroke-width"&&d===0&&(d=1.0E-6);this.symbolName&&/^(x|y|r|start|end|innerR)/.test(c)&&(n||(this.symbolAttr(a),n=!0),j=!0);if(m&&/^(width|height|visibility|x|y|d)$/.test(c))for(e=m.length;e--;)F(m[e],c,d);if((c==="width"||c==="height")&&h==="rect"&&d<0)d=0;c==="text"?
(this.textStr=d,this.added&&i.buildText(this)):j||F(g,c,d);if(l&&(c==="x"||c==="y"||c==="translateX"||c==="translateY"||c==="visibility")){e=l.length?l:[this];f=e.length;var t;for(t=0;t<f;t++)l=e[t],j=l.getBBox(),l=l.htmlNode,C(l,E(this.styles,{left:j.x+(this.translateX||0)+oa,top:j.y+(this.translateY||0)+oa})),c==="visibility"&&C(l,{visibility:d})}}return x},symbolAttr:function(a){var b=this;l("x,y,r,start,end,width,height,innerR".split(","),function(c){b[c]=n(a[c],b[c])});b.attr({d:b.renderer.symbols[b.symbolName](z(b.x*
2)/2,z(b.y*2)/2,b.r,{start:b.start,end:b.end,width:b.width,height:b.height,innerR:b.innerR})})},clip:function(a){return this.attr("clip-path","url("+this.renderer.url+"#"+a.id+")")},crisp:function(a,b,c,d,e){var f,g={},h={},i,a=a||this.strokeWidth||0;i=a%2/2;h.x=Ia(b||this.x||0)+i;h.y=Ia(c||this.y||0)+i;h.width=Ia((d||this.width||0)-2*i);h.height=Ia((e||this.height||0)-2*i);h.strokeWidth=a;for(f in h)this[f]!==h[f]&&(this[f]=g[f]=h[f]);return g},css:function(a){var b=this.element,b=a&&a.width&&b.nodeName===
"text",c,d="",e=function(a,b){return"-"+b.toLowerCase()};if(a&&a.color)a.fill=a.color;this.styles=a=E(this.styles,a);if(Hb&&!Fb)b&&delete a.width,C(this.element,a);else{for(c in a)d+=c.replace(/([A-Z])/g,e)+":"+a[c]+";";this.attr({style:d})}b&&this.added&&this.renderer.buildText(this);return this},on:function(a,b){var c=b;Oa&&a==="click"&&(a="touchstart",c=function(a){a.preventDefault();b()});this.element["on"+a]=c;return this},translate:function(a,b){return this.attr({translateX:a,translateY:b})},
invert:function(){this.inverted=!0;this.updateTransform();return this},updateTransform:function(){var a=this.translateX||0,b=this.translateY||0,c=this.inverted,d=this.rotation,e=[];c&&(a+=this.attr("width"),b+=this.attr("height"));(a||b)&&e.push("translate("+a+","+b+")");c?e.push("rotate(90) scale(-1,1)"):d&&e.push("rotate("+d+" "+this.x+" "+this.y+")");e.length&&F(this.element,"transform",e.join(" "))},toFront:function(){var a=this.element;a.parentNode.appendChild(a);return this},align:function(a,
b,c){a?(this.alignOptions=a,this.alignByTranslate=b,c||this.renderer.alignedObjects.push(this)):(a=this.alignOptions,b=this.alignByTranslate);var c=n(c,this.renderer),d=a.align,e=a.verticalAlign,f=(c.x||0)+(a.x||0),g=(c.y||0)+(a.y||0),h={};/^(right|center)$/.test(d)&&(f+=(c.width-(a.width||0))/{right:1,center:2}[d]);h[b?"translateX":"x"]=z(f);/^(bottom|middle)$/.test(e)&&(g+=(c.height-(a.height||0))/({bottom:1,middle:2}[e]||1));h[b?"translateY":"y"]=z(g);this[this.placed?"animate":"attr"](h);this.placed=
!0;this.alignAttr=h;return this},getBBox:function(){var a,b,c,d=this.rotation,e=d*Gb;try{a=E({},this.element.getBBox())}catch(f){a={width:0,height:0}}b=a.width;c=a.height;if(d)a.width=ya(c*ma(e))+ya(b*S(e)),a.height=ya(c*S(e))+ya(b*ma(e));return a},show:function(){return this.attr({visibility:Pa})},hide:function(){return this.attr({visibility:Ja})},add:function(a){var b=this.renderer,c=a||b,d=c.element||b.box,e=d.childNodes,f=this.element,g=F(f,"zIndex");this.parentInverted=a&&a.inverted;this.textStr!==
void 0&&b.buildText(this);if(a&&this.htmlNode){if(!a.htmlNode)a.htmlNode=[];a.htmlNode.push(this)}if(g)c.handleZ=!0,g=K(g);if(c.handleZ)for(c=0;c<e.length;c++)if(a=e[c],b=F(a,"zIndex"),a!==f&&(K(b)>g||!q(g)&&q(b)))return d.insertBefore(f,a),this;d.appendChild(f);this.added=!0;return this},destroy:function(){var a=this.element||{},b=this.shadows,c=a.parentNode,d,e;a.onclick=a.onmouseout=a.onmouseover=a.onmousemove=null;Eb(this);if(this.clipPath)this.clipPath=this.clipPath.destroy();if(this.stops){for(e=
0;e<this.stops.length;e++)this.stops[e]=this.stops[e].destroy();this.stops=null}c&&c.removeChild(a);b&&l(b,function(a){(c=a.parentNode)&&c.removeChild(a)});jb(this.renderer.alignedObjects,this);for(d in this)delete this[d];return null},empty:function(){for(var a=this.element,b=a.childNodes,c=b.length;c--;)a.removeChild(b[c])},shadow:function(a,b){var c=[],d,e,f=this.element,g=this.parentInverted?"(-1,-1)":"(1,1)";if(a){for(d=1;d<=3;d++)e=f.cloneNode(0),F(e,{isShadow:"true",stroke:"rgb(0, 0, 0)","stroke-opacity":0.05*
d,"stroke-width":7-2*d,transform:"translate"+g,fill:X}),b?b.element.appendChild(e):f.parentNode.insertBefore(e,f),c.push(e);this.shadows=c}return this}};var Rb=function(){this.init.apply(this,arguments)};Rb.prototype={Element:lb,init:function(a,b,c,d){var e=location,f;f=this.createElement("svg").attr({xmlns:"http://www.w3.org/2000/svg",version:"1.1"});a.appendChild(f.element);this.box=f.element;this.boxWrapper=f;this.alignedObjects=[];this.url=Hb?"":e.href.replace(/#.*?$/,"");this.defs=this.createElement("defs").add();
this.forExport=d;this.gradients=[];this.setSize(b,c,!1)},destroy:function(){var a,b=this.gradients,c=this.defs;this.box=null;this.boxWrapper=this.boxWrapper.destroy();if(b){for(a=0;a<b.length;a++)this.gradients[a]=b[a].destroy();this.gradients=null}if(c)this.defs=c.destroy();return this.alignedObjects=null},createElement:function(a){var b=new this.Element;b.init(this,a);return b},buildText:function(a){for(var b=a.element,c=n(a.textStr,"").toString().replace(/<(b|strong)>/g,'<span style="font-weight:bold">').replace(/<(i|em)>/g,
'<span style="font-style:italic">').replace(/<a/g,"<span").replace(/<\/(b|strong|i|em|a)>/g,"</span>").split(/<br.*?>/g),d=b.childNodes,e=/style="([^"]+)"/,f=/href="([^"]+)"/,g=F(b,"x"),h=a.styles,i=h&&a.useHTML&&!this.forExport,j=a.htmlNode,m=h&&K(h.width),w=h&&h.lineHeight,q,x=d.length;x--;)b.removeChild(d[x]);m&&!a.added&&this.box.appendChild(b);l(c,function(c,d){var h,i=0,j,c=c.replace(/<span/g,"|||<span").replace(/<\/span>/g,"</span>|||");h=c.split("|||");l(h,function(c){if(c!==""||h.length===
1){var l={},n=G.createElementNS("http://www.w3.org/2000/svg","tspan");e.test(c)&&F(n,"style",c.match(e)[1].replace(/(;| |^)color([ :])/,"$1fill$2"));f.test(c)&&(F(n,"onclick",'location.href="'+c.match(f)[1]+'"'),C(n,{cursor:"pointer"}));c=(c.replace(/<(.|\n)*?>/g,"")||" ").replace(/&lt;/g,"<").replace(/&gt;/g,">");n.appendChild(G.createTextNode(c));i?l.dx=3:l.x=g;if(!i){if(d){!Fb&&a.renderer.forExport&&C(n,{display:"block"});j=ka.getComputedStyle&&K(ka.getComputedStyle(q,null).getPropertyValue("line-height"));
if(!j||isNaN(j))j=w||q.offsetHeight||18;F(n,"dy",j)}q=n}F(n,l);b.appendChild(n);i++;if(m)for(var c=c.replace(/-/g,"- ").split(" "),t,x=[];c.length||x.length;)t=b.getBBox().width,l=t>m,!l||c.length===1?(c=x,x=[],c.length&&(n=G.createElementNS("http://www.w3.org/2000/svg","tspan"),F(n,{dy:w||16,x:g}),b.appendChild(n),t>m&&(m=t))):(n.removeChild(n.firstChild),x.unshift(c.pop())),c.length&&n.appendChild(G.createTextNode(c.join(" ").replace(/- /g,"-")))}})});if(i){if(!j)j=a.htmlNode=W("span",null,E(h,
{position:fb,top:0,left:0}),this.box.parentNode);j.innerHTML=a.textStr;for(x=d.length;x--;)d[x].style.visibility=Ja}},crispLine:function(a,b){a[1]===a[4]&&(a[1]=a[4]=z(a[1])+b%2/2);a[2]===a[5]&&(a[2]=a[5]=z(a[2])+b%2/2);return a},path:function(a){return this.createElement("path").attr({d:a,fill:X})},circle:function(a,b,c){a=Ga(a)?a:{x:a,y:b,r:c};return this.createElement("circle").attr(a)},arc:function(a,b,c,d,e,f){if(Ga(a))b=a.y,c=a.r,d=a.innerR,e=a.start,f=a.end,a=a.x;return this.symbol("arc",a||
0,b||0,c||0,{innerR:d||0,start:e||0,end:f||0})},rect:function(a,b,c,d,e,f){if(Ga(a))b=a.y,c=a.width,d=a.height,e=a.r,f=a.strokeWidth,a=a.x;e=this.createElement("rect").attr({rx:e,ry:e,fill:X});return e.attr(e.crisp(f,a,b,Z(c,0),Z(d,0)))},setSize:function(a,b,c){var d=this.alignedObjects,e=d.length;this.width=a;this.height=b;for(this.boxWrapper[n(c,!0)?"animate":"attr"]({width:a,height:b});e--;)d[e].align()},g:function(a){var b=this.createElement("g");return q(a)?b.attr({"class":rb+a}):b},image:function(a,
b,c,d,e){var f={preserveAspectRatio:X};arguments.length>1&&E(f,{x:b,y:c,width:d,height:e});f=this.createElement("image").attr(f);f.element.setAttributeNS?f.element.setAttributeNS("http://www.w3.org/1999/xlink","href",a):f.element.setAttribute("hc-svg-href",a);return f},symbol:function(a,b,c,d,e){var f,g=this.symbols[a],g=g&&g(z(b),z(c),d,e),h=/^url\((.*?)\)$/,i;if(g)f=this.path(g),E(f,{symbolName:a,x:b,y:c,r:d}),e&&E(f,e);else if(h.test(a)){var j=function(a,b){a.attr({width:b[0],height:b[1]}).translate(-z(b[0]/
2),-z(b[1]/2))};i=a.match(h)[1];a=Vb[i];f=this.image(i).attr({x:b,y:c});a?j(f,a):(f.attr({width:0,height:0}),W("img",{onload:function(){j(f,Vb[i]=[this.width,this.height])},src:i}))}else f=this.circle(b,c,d);return f},symbols:{square:function(a,b,c){c*=0.707;return[va,a-c,b-c,aa,a+c,b-c,a+c,b+c,a-c,b+c,"Z"]},triangle:function(a,b,c){return[va,a,b-1.33*c,aa,a+c,b+0.67*c,a-c,b+0.67*c,"Z"]},"triangle-down":function(a,b,c){return[va,a,b+1.33*c,aa,a-c,b-0.67*c,a+c,b-0.67*c,"Z"]},diamond:function(a,b,c){return[va,
a,b-c,aa,a+c,b,a,b+c,a-c,b,"Z"]},arc:function(a,b,c,d){var e=d.start,f=d.end-1.0E-6,g=d.innerR,h=S(e),i=ma(e),j=S(f),f=ma(f),d=d.end-e<qa?0:1;return[va,a+c*h,b+c*i,"A",c,c,0,d,1,a+c*j,b+c*f,aa,a+g*j,b+g*f,"A",g,g,0,d,0,a+g*h,b+g*i,"Z"]}},clipRect:function(a,b,c,d){var e=rb+gc++,f=this.createElement("clipPath").attr({id:e}).add(this.defs),a=this.rect(a,b,c,d,0).add(f);a.id=e;a.clipPath=f;return a},color:function(a,b,c){var d,e=/^rgba/;if(a&&a.linearGradient){var f=this,b=a.linearGradient,c=rb+gc++,
g,h,i;g=f.createElement("linearGradient").attr({id:c,gradientUnits:"userSpaceOnUse",x1:b[0],y1:b[1],x2:b[2],y2:b[3]}).add(f.defs);f.gradients.push(g);g.stops=[];l(a.stops,function(a){e.test(a[1])?(d=Fa(a[1]),h=d.get("rgb"),i=d.get("a")):(h=a[1],i=1);a=f.createElement("stop").attr({offset:a[0],"stop-color":h,"stop-opacity":i}).add(g);g.stops.push(a)});return"url("+this.url+"#"+c+")"}else return e.test(a)?(d=Fa(a),F(b,c+"-opacity",d.get("a")),d.get("rgb")):(b.removeAttribute(c+"-opacity"),a)},text:function(a,
b,c,d){var e=sa.chart.style,b=z(n(b,0)),c=z(n(c,0)),a=this.createElement("text").attr({x:b,y:c,text:a}).css({fontFamily:e.fontFamily,fontSize:e.fontSize});a.x=b;a.y=c;a.useHTML=d;return a}};Sb=Rb;if(!Fb)U=ca(lb,{init:function(a,b){var c=["<",b,' filled="f" stroked="f"'],d=["position: ",fb,";"];(b==="shape"||b===Za)&&d.push("left:0;top:0;width:10px;height:10px;");Ta&&d.push("visibility: ",b===Za?Ja:Pa);c.push(' style="',d.join(""),'"/>');if(b)c=b===Za||b==="span"||b==="img"?c.join(""):a.prepVML(c),
this.element=W(c);this.renderer=a},add:function(a){var b=this.renderer,c=this.element,d=b.box,d=a?a.element||a:d;a&&a.inverted&&b.invertChild(c,d);Ta&&d.gVis===Ja&&C(c,{visibility:Ja});d.appendChild(c);this.added=!0;this.alignOnAdd&&this.updateTransform();return this},attr:function(a,b){var c,d,e,f=this.element||{},g=f.style,h=f.nodeName,i=this.renderer,j=this.symbolName,m,l,n=this.shadows,x=this;Ya(a)&&q(b)&&(c=a,a={},a[c]=b);if(Ya(a))c=a,x=c==="strokeWidth"||c==="stroke-width"?this.strokeweight:
this[c];else for(c in a){d=a[c];m=!1;if(j&&/^(x|y|r|start|end|width|height|innerR)/.test(c))l||(this.symbolAttr(a),l=!0),m=!0;else if(c==="d"){d=d||[];this.d=d.join(" ");e=d.length;for(m=[];e--;)m[e]=fa(d[e])?z(d[e]*10)-5:d[e]==="Z"?"x":d[e];d=m.join(" ")||"x";f.path=d;if(n)for(e=n.length;e--;)n[e].path=d;m=!0}else if(c==="zIndex"||c==="visibility"){if(Ta&&c==="visibility"&&h==="DIV"){f.gVis=d;m=f.childNodes;for(e=m.length;e--;)C(m[e],{visibility:d});d===Pa&&(d=null)}d&&(g[c]=d);m=!0}else if(/^(width|height)$/.test(c))this[c]=
d,this.updateClipping?(this[c]=d,this.updateClipping()):g[c]=d,m=!0;else if(/^(x|y)$/.test(c))this[c]=d,f.tagName==="SPAN"?this.updateTransform():g[{x:"left",y:"top"}[c]]=d;else if(c==="class")f.className=d;else if(c==="stroke")d=i.color(d,f,c),c="strokecolor";else if(c==="stroke-width"||c==="strokeWidth")f.stroked=d?!0:!1,c="strokeweight",this[c]=d,fa(d)&&(d+=oa);else if(c==="dashstyle")(f.getElementsByTagName("stroke")[0]||W(i.prepVML(["<stroke/>"]),null,null,f))[c]=d||"solid",this.dashstyle=d,
m=!0;else if(c==="fill")h==="SPAN"?g.color=d:(f.filled=d!==X?!0:!1,d=i.color(d,f,c),c="fillcolor");else if(c==="translateX"||c==="translateY"||c==="rotation"||c==="align")c==="align"&&(c="textAlign"),this[c]=d,this.updateTransform(),m=!0;else if(c==="text")this.bBox=null,f.innerHTML=d,m=!0;if(n&&c==="visibility")for(e=n.length;e--;)n[e].style[c]=d;m||(Ta?f[c]=d:F(f,c,d))}return x},clip:function(a){var b=this,c=a.members;c.push(b);b.destroyClip=function(){jb(c,b)};return b.css(a.getCSS(b.inverted))},
css:function(a){var b=this.element;if(b=a&&b.tagName==="SPAN"&&a.width)delete a.width,this.textWidth=b,this.updateTransform();this.styles=E(this.styles,a);C(this.element,a);return this},destroy:function(){this.destroyClip&&this.destroyClip();return lb.prototype.destroy.apply(this)},empty:function(){for(var a=this.element.childNodes,b=a.length,c;b--;)c=a[b],c.parentNode.removeChild(c)},getBBox:function(){var a=this.element,b=this.bBox;if(!b){if(a.nodeName==="text")a.style.position=fb;b=this.bBox={x:a.offsetLeft,
y:a.offsetTop,width:a.offsetWidth,height:a.offsetHeight}}return b},on:function(a,b){this.element["on"+a]=function(){var a=ka.event;a.target=a.srcElement;b(a)};return this},updateTransform:function(){if(this.added){var a=this,b=a.element,c=a.translateX||0,d=a.translateY||0,e=a.x||0,f=a.y||0,g=a.textAlign||"left",h={left:0,center:0.5,right:1}[g],i=g&&g!=="left";(c||d)&&a.css({marginLeft:c,marginTop:d});a.inverted&&l(b.childNodes,function(c){a.renderer.invertChild(c,b)});if(b.tagName==="SPAN"){var j,
m,c=a.rotation,n;j=0;var d=1,N=0,x;n=K(a.textWidth);var t=a.xCorr||0,r=a.yCorr||0,$=[c,g,b.innerHTML,a.textWidth].join(",");if($!==a.cTT)q(c)&&(j=c*Gb,d=S(j),N=ma(j),C(b,{filter:c?["progid:DXImageTransform.Microsoft.Matrix(M11=",d,", M12=",-N,", M21=",N,", M22=",d,", sizingMethod='auto expand')"].join(""):X})),j=b.offsetWidth,m=b.offsetHeight,j>n&&(C(b,{width:n+oa,display:"block",whiteSpace:"normal"}),j=n),n=z((K(b.style.fontSize)||12)*1.2),t=d<0&&-j,r=N<0&&-m,x=d*N<0,t+=N*n*(x?1-h:h),r-=d*n*(c?x?
h:1-h:1),i&&(t-=j*h*(d<0?-1:1),c&&(r-=m*h*(N<0?-1:1)),C(b,{textAlign:g})),a.xCorr=t,a.yCorr=r;C(b,{left:e+t,top:f+r});a.cTT=$}}else this.alignOnAdd=!0},shadow:function(a,b){var c=[],d,e=this.element,f=this.renderer,g,h=e.style,i,j=e.path;j&&typeof j.value!=="string"&&(j="x");if(a){for(d=1;d<=3;d++)i=['<shape isShadow="true" strokeweight="',7-2*d,'" filled="false" path="',j,'" coordsize="100,100" style="',e.style.cssText,'" />'],g=W(f.prepVML(i),null,{left:K(h.left)+1,top:K(h.top)+1}),i=['<stroke color="black" opacity="',
0.05*d,'"/>'],W(f.prepVML(i),null,null,g),b?b.element.appendChild(g):e.parentNode.insertBefore(g,e),c.push(g);this.shadows=c}return this}}),y=function(){this.init.apply(this,arguments)},y.prototype=Q(Rb.prototype,{Element:U,isIE8:Sa.indexOf("MSIE 8.0")>-1,init:function(a,b,c){var d;this.alignedObjects=[];d=this.createElement(Za);a.appendChild(d.element);this.box=d.element;this.boxWrapper=d;this.setSize(b,c,!1);if(!G.namespaces.hcv)G.namespaces.add("hcv","urn:schemas-microsoft-com:vml"),G.createStyleSheet().cssText=
"hcv\\:fill, hcv\\:path, hcv\\:shape, hcv\\:stroke{ behavior:url(#default#VML); display: inline-block; } "},clipRect:function(a,b,c,d){var e=this.createElement();return E(e,{members:[],left:a,top:b,width:c,height:d,getCSS:function(a){var b=this.top,c=this.left,d=c+this.width,e=b+this.height,b={clip:"rect("+z(a?c:b)+"px,"+z(a?e:d)+"px,"+z(a?d:e)+"px,"+z(a?b:c)+"px)"};!a&&Ta&&E(b,{width:d+oa,height:e+oa});return b},updateClipping:function(){l(e.members,function(a){a.css(e.getCSS(a.inverted))})}})},
color:function(a,b,c){var d,e=/^rgba/;if(a&&a.linearGradient){var f,g,h=a.linearGradient,i,j,m,n;l(a.stops,function(a,b){e.test(a[1])?(d=Fa(a[1]),f=d.get("rgb"),g=d.get("a")):(f=a[1],g=1);b?(m=f,n=g):(i=f,j=g)});a=90-V.atan((h[3]-h[1])/(h[2]-h[0]))*180/qa;a=["<",c,' colors="0% ',i,",100% ",m,'" angle="',a,'" opacity="',n,'" o:opacity2="',j,'" type="gradient" focus="100%" />'];W(this.prepVML(a),null,null,b)}else if(e.test(a)&&b.tagName!=="IMG")return d=Fa(a),a=["<",c,' opacity="',d.get("a"),'"/>'],
W(this.prepVML(a),null,null,b),d.get("rgb");else{b=b.getElementsByTagName(c);if(b.length)b[0].opacity=1;return a}},prepVML:function(a){var b=this.isIE8,a=a.join("");b?(a=a.replace("/>",' xmlns="urn:schemas-microsoft-com:vml" />'),a=a.indexOf('style="')===-1?a.replace("/>",' style="display:inline-block;behavior:url(#default#VML);" />'):a.replace('style="','style="display:inline-block;behavior:url(#default#VML);')):a=a.replace("<","<hcv:");return a},text:function(a,b,c){var d=sa.chart.style;return this.createElement("span").attr({text:a,
x:z(b),y:z(c)}).css({whiteSpace:"nowrap",fontFamily:d.fontFamily,fontSize:d.fontSize})},path:function(a){return this.createElement("shape").attr({coordsize:"100 100",d:a})},circle:function(a,b,c){return this.symbol("circle").attr({x:a,y:b,r:c})},g:function(a){var b;a&&(b={className:rb+a,"class":rb+a});return this.createElement(Za).attr(b)},image:function(a,b,c,d,e){var f=this.createElement("img").attr({src:a});arguments.length>1&&f.css({left:b,top:c,width:d,height:e});return f},rect:function(a,b,
c,d,e,f){if(Ga(a))b=a.y,c=a.width,d=a.height,e=a.r,f=a.strokeWidth,a=a.x;var g=this.symbol("rect");g.r=e;return g.attr(g.crisp(f,a,b,Z(c,0),Z(d,0)))},invertChild:function(a,b){var c=b.style;C(a,{flip:"x",left:K(c.width)-10,top:K(c.height)-10,rotation:-90})},symbols:{arc:function(a,b,c,d){var e=d.start,f=d.end,g=S(e),h=ma(e),i=S(f),j=ma(f),d=d.innerR,m=0.07/c,l=d&&0.1/d||0;if(f-e===0)return["x"];else 2*qa-f+e<m?i=-m:f-e<l&&(i=S(e+l));return["wa",a-c,b-c,a+c,b+c,a+c*g,b+c*h,a+c*i,b+c*j,"at",a-d,b-d,
a+d,b+d,a+d*i,b+d*j,a+d*g,b+d*h,"x","e"]},circle:function(a,b,c){return["wa",a-c,b-c,a+c,b+c,a+c,b,a+c,b,"e"]},rect:function(a,b,c,d){if(!q(d))return[];var e=d.width,d=d.height,f=a+e,g=b+d,c=Ka(c,e,d);return[va,a+c,b,aa,f-c,b,"wa",f-2*c,b,f,b+2*c,f-c,b,f,b+c,aa,f,g-c,"wa",f-2*c,g-2*c,f,g,f,g-c,f-c,g,aa,a+c,g,"wa",a,g-2*c,a+2*c,g,a+c,g,a,g-c,aa,a,b+c,"wa",a,b,a+2*c,b+2*c,a,b+c,a+c,b,"x","e"]}}}),Sb=y;yb.prototype.callbacks=[];var Xa=function(){};Xa.prototype={init:function(a,b){var c=a.chart.counters,
d;this.series=a;this.applyOptions(b);this.pointAttr={};if(a.options.colorByPoint){d=a.chart.options.colors;if(!this.options)this.options={};this.color=this.options.color=this.color||d[c.color++];c.wrapColor(d.length)}a.chart.pointCount++;return this},applyOptions:function(a){var b=this.series;this.config=a;if(fa(a)||a===null)this.y=a;else if(Ga(a)&&!fa(a.length))E(this,a),this.options=a;else if(Ya(a[0]))this.name=a[0],this.y=a[1];else if(fa(a[0]))this.x=a[0],this.y=a[1];if(this.x===ra)this.x=b.autoIncrement()},
destroy:function(){var a=this,b=a.series,c=b.chart.hoverPoints,d;b.chart.pointCount--;c&&(a.setState(),jb(c,a));if(a===b.chart.hoverPoint)a.onMouseOut();Na(a);l("graphic,tracker,group,dataLabel,connector,shadowGroup".split(","),function(b){a[b]&&a[b].destroy()});a.legendItem&&a.series.chart.legend.destroyItem(a);for(d in a)a[d]=null},getLabelConfig:function(){return{x:this.category,y:this.y,series:this.series,point:this,percentage:this.percentage,total:this.total||this.stackTotal}},select:function(a,
b){var c=this,d=c.series.chart,a=n(a,!c.selected);c.firePointEvent(a?"select":"unselect",{accumulate:b},function(){c.selected=a;c.setState(a&&"select");b||l(d.getSelectedPoints(),function(a){if(a.selected&&a!==c)a.selected=!1,a.setState(pa),a.firePointEvent("unselect")})})},onMouseOver:function(){var a=this.series.chart,b=a.tooltip,c=a.hoverPoint;if(c&&c!==this)c.onMouseOut();this.firePointEvent("mouseOver");b&&!b.shared&&b.refresh(this);this.setState(xa);a.hoverPoint=this},onMouseOut:function(){this.firePointEvent("mouseOut");
this.setState();this.series.chart.hoverPoint=null},tooltipFormatter:function(a){var b=this.series;return['<span style="color:'+b.color+'">',this.name||b.name,"</span>: ",!a?"<b>x = "+(this.name||this.x)+",</b> ":"","<b>",!a?"y = ":"",this.y,"</b>"].join("")},update:function(a,b,c){var d=this,e=d.series,f=d.graphic,g=e.chart,b=n(b,!0);d.firePointEvent("update",{options:a},function(){d.applyOptions(a);Ga(a)&&(e.getAttribs(),f&&f.attr(d.pointAttr[e.state]));e.isDirty=!0;b&&g.redraw(c)})},remove:function(a,
b){var c=this,d=c.series,e=d.chart,f=d.data;kb(b,e);a=n(a,!0);c.firePointEvent("remove",null,function(){jb(f,c);c.destroy();d.isDirty=!0;a&&e.redraw()})},firePointEvent:function(a,b,c){var d=this,e=this.series.options;(e.point.events[a]||d.options&&d.options.events&&d.options.events[a])&&this.importEvents();a==="click"&&e.allowPointSelect&&(c=function(a){d.select(null,a.ctrlKey||a.metaKey||a.shiftKey)});ga(this,a,b,c)},importEvents:function(){if(!this.hasImportedEvents){var a=Q(this.series.options.point,
this.options).events,b;this.events=a;for(b in a)ha(this,b,a[b]);this.hasImportedEvents=!0}},setState:function(a){var b=this.series,c=b.options.states,d=ia[b.type].marker&&b.options.marker,e=d&&!d.enabled,f=(d=d&&d.states[a])&&d.enabled===!1,g=b.stateMarkerGraphic,h=b.chart,i=this.pointAttr,a=a||pa;if(!(a===this.state||this.selected&&a!=="select"||c[a]&&c[a].enabled===!1||a&&(f||e&&!d.enabled))){if(this.graphic)this.graphic.attr(i[a]);else{if(a){if(!g)b.stateMarkerGraphic=g=h.renderer.circle(0,0,i[a].r).attr(i[a]).add(b.group);
g.translate(this.plotX,this.plotY)}if(g)g[a?"show":"hide"]()}this.state=a}}};var ba=function(){};ba.prototype={isCartesian:!0,type:"line",pointClass:Xa,pointAttrToOptions:{stroke:"lineColor","stroke-width":"lineWidth",fill:"fillColor",r:"radius"},init:function(a,b){var c,d;d=a.series.length;this.chart=a;b=this.setOptions(b);E(this,{index:d,options:b,name:b.name||"Series "+(d+1),state:pa,pointAttr:{},visible:b.visible!==!1,selected:b.selected===!0});d=b.events;for(c in d)ha(this,c,d[c]);if(d&&d.click||
b.point&&b.point.events&&b.point.events.click||b.allowPointSelect)a.runTrackerClick=!0;this.getColor();this.getSymbol();this.setData(b.data,!1)},autoIncrement:function(){var a=this.options,b=this.xIncrement,b=n(b,a.pointStart,0);this.pointInterval=n(this.pointInterval,a.pointInterval,1);this.xIncrement=b+this.pointInterval;return b},cleanData:function(){var a=this.chart,b=this.data,c,d,e=a.smallestInterval,f,g;pc(b,function(a,b){return a.x-b.x});if(this.options.connectNulls)for(g=b.length-1;g>=0;g--)b[g].y===
null&&b[g-1]&&b[g+1]&&b.splice(g,1);for(g=b.length-1;g>=0;g--)if(b[g-1]&&(f=b[g].x-b[g-1].x,f>0&&(d===ra||f<d)))d=f,c=g;if(e===ra||d<e)a.smallestInterval=d;this.closestPoints=c},getSegments:function(){var a=-1,b=[],c=this.data;l(c,function(d,e){d.y===null?(e>a+1&&b.push(c.slice(a+1,e)),a=e):e===c.length-1&&b.push(c.slice(a+1,e+1))});this.segments=b},setOptions:function(a){var b=this.chart.options.plotOptions;return Q(b[this.type],b.series,a)},getColor:function(){var a=this.chart.options.colors,b=
this.chart.counters;this.color=this.options.color||a[b.color++]||"#0000ff";b.wrapColor(a.length)},getSymbol:function(){var a=this.chart.options.symbols,b=this.chart.counters;this.symbol=this.options.marker.symbol||a[b.symbol++];b.wrapSymbol(a.length)},addPoint:function(a,b,c,d){var e=this.data,f=this.graph,g=this.area,h=this.chart,a=(new this.pointClass).init(this,a);kb(d,h);if(f&&c)f.shift=c;if(g)g.shift=c,g.isArea=!0;b=n(b,!0);e.push(a);c&&e[0].remove(!1);this.getAttribs();this.isDirty=!0;b&&h.redraw()},
setData:function(a,b){var c=this,d=c.data,e=c.initialColor,f=c.chart,g=d&&d.length||0;c.xIncrement=null;if(q(e))f.counters.color=e;for(a=qb(tb(a||[]),function(a){return(new c.pointClass).init(c,a)});g--;)d[g].destroy();c.data=a;c.cleanData();c.getSegments();c.getAttribs();c.isDirty=!0;f.isDirtyBox=!0;n(b,!0)&&f.redraw(!1)},remove:function(a,b){var c=this,d=c.chart,a=n(a,!0);if(!c.isRemoving)c.isRemoving=!0,ga(c,"remove",null,function(){c.destroy();d.isDirtyLegend=d.isDirtyBox=!0;a&&d.redraw(b)});
c.isRemoving=!1},translate:function(){for(var a=this.chart,b=this.options.stacking,c=this.xAxis.categories,d=this.yAxis,e=this.data,f=e.length;f--;){var g=e[f],h=g.x,i=g.y,j=g.low,m=d.stacks[(i<0?"-":"")+this.stackKey];g.plotX=this.xAxis.translate(h);if(b&&this.visible&&m&&m[h])j=m[h],h=j.total,j.cum=j=j.cum-i,i=j+i,b==="percent"&&(j=h?j*100/h:0,i=h?i*100/h:0),g.percentage=h?g.y*100/h:0,g.stackTotal=h;if(q(j))g.yBottom=d.translate(j,0,1,0,1);if(i!==null)g.plotY=d.translate(i,0,1,0,1);g.clientX=a.inverted?
a.plotHeight-g.plotX:g.plotX;g.category=c&&c[g.x]!==ra?c[g.x]:g.x}},setTooltipPoints:function(a){var b=this.chart,c=b.inverted,d=[],e=z((c?b.plotTop:b.plotLeft)+b.plotSizeX),f,g,h=[];if(a)this.tooltipPoints=null;l(this.segments,function(a){d=d.concat(a)});this.xAxis&&this.xAxis.reversed&&(d=d.reverse());l(d,function(a,b){f=d[b-1]?d[b-1]._high+1:0;for(g=a._high=d[b+1]?Ia((a.plotX+(d[b+1]?d[b+1].plotX:e))/2):e;f<=g;)h[c?e-f++:f++]=a});this.tooltipPoints=h},onMouseOver:function(){var a=this.chart,b=
a.hoverSeries;if(Oa||!a.mouseIsDown){if(b&&b!==this)b.onMouseOut();this.options.events.mouseOver&&ga(this,"mouseOver");this.tracker&&this.tracker.toFront();this.setState(xa);a.hoverSeries=this}},onMouseOut:function(){var a=this.options,b=this.chart,c=b.tooltip,d=b.hoverPoint;if(d)d.onMouseOut();this&&a.events.mouseOut&&ga(this,"mouseOut");c&&!a.stickyTracking&&c.hide();this.setState();b.hoverSeries=null},animate:function(a){var b=this.chart,c=this.clipRect,d=this.options.animation;d&&!Ga(d)&&(d={});
if(a){if(!c.isAnimating)c.attr("width",0),c.isAnimating=!0}else c.animate({width:b.plotSizeX},d),this.animate=null},drawPoints:function(){var a,b=this.data,c=this.chart,d,e,f,g,h,i;if(this.options.marker.enabled)for(f=b.length;f--;)if(g=b[f],d=g.plotX,e=g.plotY,i=g.graphic,e!==ra&&!isNaN(e))a=g.pointAttr[g.selected?"select":pa],h=a.r,i?i.animate({x:d,y:e,r:h}):g.graphic=c.renderer.symbol(n(g.marker&&g.marker.symbol,this.symbol),d,e,h).attr(a).add(this.group)},convertAttribs:function(a,b,c,d){var e=
this.pointAttrToOptions,f,g,h={},a=a||{},b=b||{},c=c||{},d=d||{};for(f in e)g=e[f],h[f]=n(a[g],b[f],c[f],d[f]);return h},getAttribs:function(){var a=this,b=ia[a.type].marker?a.options.marker:a.options,c=b.states,d=c[xa],e,f=a.color,g={stroke:f,fill:f},h=a.data,i=[],j,m=a.pointAttrToOptions,n;a.options.marker?(d.radius=d.radius||b.radius+2,d.lineWidth=d.lineWidth||b.lineWidth+1):d.color=d.color||Fa(d.color||f).brighten(d.brightness).get();i[pa]=a.convertAttribs(b,g);l([xa,"select"],function(b){i[b]=
a.convertAttribs(c[b],i[pa])});a.pointAttr=i;for(f=h.length;f--;){g=h[f];if((b=g.options&&g.options.marker||g.options)&&b.enabled===!1)b.radius=0;e=!1;if(g.options)for(n in m)q(b[m[n]])&&(e=!0);if(e){j=[];c=b.states||{};e=c[xa]=c[xa]||{};if(!a.options.marker)e.color=Fa(e.color||g.options.color).brighten(e.brightness||d.brightness).get();j[pa]=a.convertAttribs(b,i[pa]);j[xa]=a.convertAttribs(c[xa],i[xa],j[pa]);j.select=a.convertAttribs(c.select,i.select,j[pa])}else j=i;g.pointAttr=j}},destroy:function(){var a=
this,b=a.chart,c=a.clipRect,d=/\/5[0-9\.]+ (Safari|Mobile)\//.test(Sa),e,f;ga(a,"destroy");Na(a);a.legendItem&&a.chart.legend.destroyItem(a);l(a.data,function(a){a.destroy()});if(c&&c!==b.clipRect)a.clipRect=c.destroy();l(["area","graph","dataLabelsGroup","group","tracker"],function(b){a[b]&&(e=d&&b==="group"?"hide":"destroy",a[b][e]())});if(b.hoverSeries===a)b.hoverSeries=null;jb(b.series,a);for(f in a)delete a[f]},drawDataLabels:function(){if(this.options.dataLabels.enabled){var a,b,c=this.data,
d=this.options,e=d.dataLabels,f,g=this.dataLabelsGroup,h=this.chart,i=h.renderer,j=h.inverted,m=this.type,w;w=d.stacking;var z=m==="column"||m==="bar",x=e.verticalAlign===null,t=e.y===null;z&&(w?(x&&(e=Q(e,{verticalAlign:"middle"})),t&&(e=Q(e,{y:{top:14,middle:4,bottom:-6}[e.verticalAlign]}))):x&&(e=Q(e,{verticalAlign:"top"})));g?g.translate(h.plotLeft,h.plotTop):g=this.dataLabelsGroup=i.g("data-labels").attr({visibility:this.visible?Pa:Ja,zIndex:6}).translate(h.plotLeft,h.plotTop).add();w=e.color;
w==="auto"&&(w=null);e.style.color=n(w,this.color,"black");l(c,function(c){var l=c.barX,o=l&&l+c.barW/2||c.plotX||-999,w=n(c.plotY,-999),p=c.dataLabel,u=e.align,x=t?c.y>=0?-6:12:e.y;f=e.formatter.call(c.getLabelConfig());a=(j?h.plotWidth-w:o)+e.x;b=(j?h.plotHeight-o:w)+x;m==="column"&&(a+={left:-1,right:1}[u]*c.barW/2||0);j&&c.y<0&&(u="right",a-=10);if(p)j&&!e.y&&(b=b+K(p.styles.lineHeight)*0.9-p.getBBox().height/2),p.attr({text:f}).animate({x:a,y:b});else if(q(f))p=c.dataLabel=i.text(f,a,b).attr({align:u,
rotation:e.rotation,zIndex:1}).css(e.style).add(g),j&&!e.y&&p.attr({y:b+K(p.styles.lineHeight)*0.9-p.getBBox().height/2});if(z&&d.stacking&&p)o=c.barY,w=c.barW,c=c.barH,p.align(e,null,{x:j?h.plotWidth-o-c:l,y:j?h.plotHeight-l-w:o,width:j?c:w,height:j?w:c})})}},drawGraph:function(){var a=this,b=a.options,c=a.graph,d=[],e,f=a.area,g=a.group,h=b.lineColor||a.color,i=b.lineWidth,j=b.dashStyle,m,w=a.chart.renderer,q=a.yAxis.getThreshold(b.threshold||0),x=/^area/.test(a.type),t=[],r=[];l(a.segments,function(c){m=
[];l(c,function(d,e){a.getPointSpline?m.push.apply(m,a.getPointSpline(c,d,e)):(m.push(e?aa:va),e&&b.step&&m.push(d.plotX,c[e-1].plotY),m.push(d.plotX,d.plotY))});c.length>1?d=d.concat(m):t.push(c[0]);if(x){var e=[],f,g=m.length;for(f=0;f<g;f++)e.push(m[f]);g===3&&e.push(aa,m[1],m[2]);if(b.stacking&&a.type!=="areaspline")for(f=c.length-1;f>=0;f--)e.push(c[f].plotX,c[f].yBottom);else e.push(aa,c[c.length-1].plotX,q,aa,c[0].plotX,q);r=r.concat(e)}});a.graphPath=d;a.singlePoints=t;if(x)e=n(b.fillColor,
Fa(a.color).setOpacity(b.fillOpacity||0.75).get()),f?f.animate({d:r}):a.area=a.chart.renderer.path(r).attr({fill:e}).add(g);if(c)Eb(c),c.animate({d:d});else if(i){c={stroke:h,"stroke-width":i};if(j)c.dashstyle=j;a.graph=w.path(d).attr(c).add(g).shadow(b.shadow)}},render:function(){var a=this,b=a.chart,c,d,e=a.options,f=e.animation,g=f&&a.animate,f=g?f&&f.duration||500:0,h=a.clipRect,i=b.renderer;if(!h&&(h=a.clipRect=!b.hasRendered&&b.clipRect?b.clipRect:i.clipRect(0,0,b.plotSizeX,b.plotSizeY),!b.clipRect))b.clipRect=
h;if(!a.group)c=a.group=i.g("series"),b.inverted&&(d=function(){c.attr({width:b.plotWidth,height:b.plotHeight}).invert()},d(),ha(b,"resize",d),ha(a,"destroy",function(){Na(b,"resize",d)})),c.clip(a.clipRect).attr({visibility:a.visible?Pa:Ja,zIndex:e.zIndex}).translate(b.plotLeft,b.plotTop).add(b.seriesGroup);a.drawDataLabels();g&&a.animate(!0);a.drawGraph&&a.drawGraph();a.drawPoints();a.options.enableMouseTracking!==!1&&a.drawTracker();g&&a.animate();setTimeout(function(){h.isAnimating=!1;if((c=a.group)&&
h!==b.clipRect&&h.renderer)c.clip(a.clipRect=b.clipRect),h.destroy()},f);a.isDirty=!1},redraw:function(){var a=this.chart,b=this.group;b&&(a.inverted&&b.attr({width:a.plotWidth,height:a.plotHeight}),b.animate({translateX:a.plotLeft,translateY:a.plotTop}));this.translate();this.setTooltipPoints(!0);this.render()},setState:function(a){var b=this.options,c=this.graph,d=b.states,b=b.lineWidth,a=a||pa;if(this.state!==a)this.state=a,d[a]&&d[a].enabled===!1||(a&&(b=d[a].lineWidth||b+1),c&&!c.dashstyle&&
c.attr({"stroke-width":b},a?0:500))},setVisible:function(a,b){var c=this.chart,d=this.legendItem,e=this.group,f=this.tracker,g=this.dataLabelsGroup,h,i=this.data,j=c.options.chart.ignoreHiddenSeries;h=this.visible;h=(this.visible=a=a===ra?!h:a)?"show":"hide";if(e)e[h]();if(f)f[h]();else for(e=i.length;e--;)if(f=i[e],f.tracker)f.tracker[h]();if(g)g[h]();d&&c.legend.colorizeItem(this,a);this.isDirty=!0;this.options.stacking&&l(c.series,function(a){if(a.options.stacking&&a.visible)a.isDirty=!0});if(j)c.isDirtyBox=
!0;b!==!1&&c.redraw();ga(this,h)},show:function(){this.setVisible(!0)},hide:function(){this.setVisible(!1)},select:function(a){this.selected=a=a===ra?!this.selected:a;if(this.checkbox)this.checkbox.checked=a;ga(this,a?"select":"unselect")},drawTracker:function(){var a=this,b=a.options,c=[].concat(a.graphPath),d=c.length,e=a.chart,f=e.options.tooltip.snap,g=a.tracker,h=b.cursor,h=h&&{cursor:h},i=a.singlePoints,j;if(d)for(j=d+1;j--;)c[j]===va&&c.splice(j+1,0,c[j+1]-f,c[j+2],aa),(j&&c[j]===va||j===d)&&
c.splice(j,0,aa,c[j-2]+f,c[j-1]);for(j=0;j<i.length;j++)d=i[j],c.push(va,d.plotX-f,d.plotY,aa,d.plotX+f,d.plotY);g?g.attr({d:c}):a.tracker=e.renderer.path(c).attr({isTracker:!0,stroke:yc,fill:X,"stroke-width":b.lineWidth+2*f,visibility:a.visible?Pa:Ja,zIndex:b.zIndex||1}).on(Oa?"touchstart":"mouseover",function(){if(e.hoverSeries!==a)a.onMouseOver()}).on("mouseout",function(){if(!b.stickyTracking)a.onMouseOut()}).css(h).add(e.trackerGroup)}};y=ca(ba);la.line=y;y=ca(ba,{type:"area"});la.area=y;y=ca(ba,
{type:"spline",getPointSpline:function(a,b,c){var d=b.plotX,e=b.plotY,f=a[c-1],g=a[c+1],h,i,j,m;if(c&&c<a.length-1){a=f.plotY;j=g.plotX;var g=g.plotY,l;h=(1.5*d+f.plotX)/2.5;i=(1.5*e+a)/2.5;j=(1.5*d+j)/2.5;m=(1.5*e+g)/2.5;l=(m-i)*(j-d)/(j-h)+e-m;i+=l;m+=l;i>a&&i>e?(i=Z(a,e),m=2*e-i):i<a&&i<e&&(i=Ka(a,e),m=2*e-i);m>g&&m>e?(m=Z(g,e),i=2*e-m):m<g&&m<e&&(m=Ka(g,e),i=2*e-m);b.rightContX=j;b.rightContY=m}c?(b=["C",f.rightContX||f.plotX,f.rightContY||f.plotY,h||d,i||e,d,e],f.rightContX=f.rightContY=null):
b=[va,d,e];return b}});la.spline=y;y=ca(y,{type:"areaspline"});la.areaspline=y;var cb=ca(ba,{type:"column",pointAttrToOptions:{stroke:"borderColor","stroke-width":"borderWidth",fill:"color",r:"borderRadius"},init:function(){ba.prototype.init.apply(this,arguments);var a=this,b=a.chart;b.hasColumn=!0;b.hasRendered&&l(b.series,function(b){if(b.type===a.type)b.isDirty=!0})},translate:function(){var a=this,b=a.chart,c=a.options,d=c.stacking,e=c.borderWidth,f=0,g=a.xAxis.reversed,h=a.xAxis.categories,i=
{},j,m;ba.prototype.translate.apply(a);l(b.series,function(b){if(b.type===a.type&&b.visible)b.options.stacking?(j=b.stackKey,i[j]===ra&&(i[j]=f++),m=i[j]):m=f++,b.columnIndex=m});var w=a.data,z=a.closestPoints,h=ya(w[1]?w[z].plotX-w[z-1].plotX:b.plotSizeX/(h&&h.length||1)),z=h*c.groupPadding,x=(h-2*z)/f,t=c.pointWidth,r=q(t)?(x-t)/2:x*c.pointPadding,y=Z(n(t,x-2*r),1),o=r+(z+((g?f-a.columnIndex:a.columnIndex)||0)*x-h/2)*(g?-1:1),A=a.yAxis.getThreshold(c.threshold||0),p=n(c.minPointLength,5);l(w,function(f){var g=
f.plotY,h=f.yBottom||A,i=f.plotX+o,j=$b(Ka(g,h)),m=$b(Z(g,h)-j),l=a.yAxis.stacks[(f.y<0?"-":"")+a.stackKey],n;d&&a.visible&&l&&l[f.x]&&l[f.x].setOffset(o,y);ya(m)<p&&(p&&(m=p,j=ya(j-A)>p?h-p:A-(g<=A?p:0)),n=j-3);E(f,{barX:i,barY:j,barW:y,barH:m});f.shapeType="rect";g=E(b.renderer.Element.prototype.crisp.apply({},[e,i,j,y,m]),{r:c.borderRadius});e%2&&(g.y-=1,g.height+=1);f.shapeArgs=g;f.trackerArgs=q(n)&&Q(f.shapeArgs,{height:Z(6,m+3),y:n})})},getSymbol:function(){},drawGraph:function(){},drawPoints:function(){var a=
this,b=a.options,c=a.chart.renderer,d,e;l(a.data,function(f){var g=f.plotY;if(g!==ra&&!isNaN(g)&&f.y!==null)d=f.graphic,e=f.shapeArgs,d?(Eb(d),d.animate(e)):f.graphic=c[f.shapeType](e).attr(f.pointAttr[f.selected?"select":pa]).add(a.group).shadow(b.shadow)})},drawTracker:function(){var a=this,b=a.chart,c=b.renderer,d,e,f=+new Date,g=a.options,h=g.cursor,i=h&&{cursor:h},j;l(a.data,function(h){e=h.tracker;d=h.trackerArgs||h.shapeArgs;delete d.strokeWidth;if(h.y!==null)e?e.attr(d):h.tracker=c[h.shapeType](d).attr({isTracker:f,
fill:yc,visibility:a.visible?Pa:Ja,zIndex:g.zIndex||1}).on(Oa?"touchstart":"mouseover",function(c){j=c.relatedTarget||c.fromElement;if(b.hoverSeries!==a&&F(j,"isTracker")!==f)a.onMouseOver();h.onMouseOver()}).on("mouseout",function(b){if(!g.stickyTracking&&(j=b.relatedTarget||b.toElement,F(j,"isTracker")!==f))a.onMouseOut()}).css(i).add(h.group||b.trackerGroup)})},animate:function(a){var b=this,c=b.data;if(!a)l(c,function(a){var c=a.graphic,a=a.shapeArgs;c&&(c.attr({height:0,y:b.yAxis.translate(0,
0,1)}),c.animate({height:a.height,y:a.y},b.options.animation))}),b.animate=null},remove:function(){var a=this,b=a.chart;b.hasRendered&&l(b.series,function(b){if(b.type===a.type)b.isDirty=!0});ba.prototype.remove.apply(a,arguments)}});la.column=cb;y=ca(cb,{type:"bar",init:function(a){a.inverted=this.inverted=!0;cb.prototype.init.apply(this,arguments)}});la.bar=y;y=ca(ba,{type:"scatter",translate:function(){var a=this;ba.prototype.translate.apply(a);l(a.data,function(b){b.shapeType="circle";b.shapeArgs=
{x:b.plotX,y:b.plotY,r:a.chart.options.tooltip.snap}})},drawTracker:function(){var a=this,b=a.options.cursor,c=b&&{cursor:b},d;l(a.data,function(b){(d=b.graphic)&&d.attr({isTracker:!0}).on("mouseover",function(){a.onMouseOver();b.onMouseOver()}).on("mouseout",function(){if(!a.options.stickyTracking)a.onMouseOut()}).css(c)})},cleanData:function(){}});la.scatter=y;y=ca(Xa,{init:function(){Xa.prototype.init.apply(this,arguments);var a=this,b;E(a,{visible:a.visible!==!1,name:n(a.name,"Slice")});b=function(){a.slice()};
ha(a,"select",b);ha(a,"unselect",b);return a},setVisible:function(a){var b=this.series.chart,c=this.tracker,d=this.dataLabel,e=this.connector,f=this.shadowGroup,g;g=(this.visible=a=a===ra?!this.visible:a)?"show":"hide";this.group[g]();if(c)c[g]();if(d)d[g]();if(e)e[g]();if(f)f[g]();this.legendItem&&b.legend.colorizeItem(this,a)},slice:function(a,b,c){var d=this.series.chart,e=this.slicedTranslation;kb(c,d);n(b,!0);a=this.sliced=q(a)?a:!this.sliced;a={translateX:a?e[0]:d.plotLeft,translateY:a?e[1]:
d.plotTop};this.group.animate(a);this.shadowGroup&&this.shadowGroup.animate(a)}});y=ca(ba,{type:"pie",isCartesian:!1,pointClass:y,pointAttrToOptions:{stroke:"borderColor","stroke-width":"borderWidth",fill:"color"},getColor:function(){this.initialColor=this.chart.counters.color},animate:function(){var a=this;l(a.data,function(b){var c=b.graphic,b=b.shapeArgs,d=-qa/2;c&&(c.attr({r:0,start:d,end:d}),c.animate({r:b.r,start:b.start,end:b.end},a.options.animation))});a.animate=null},translate:function(){var a=
0,b=-0.25,c=this.options,d=c.slicedOffset,e=d+c.borderWidth,f=c.center.concat([c.size,c.innerSize||0]),g=this.chart,h=g.plotWidth,i=g.plotHeight,j,m,n,q=this.data,x=2*qa,t,r=Ka(h,i),y,o,A,p=c.dataLabels.distance,f=qb(f,function(a,b){return(y=/%$/.test(a))?[h,i,r,r][b]*K(a)/100:a});this.getX=function(a,b){n=V.asin((a-f[1])/(f[2]/2+p));return f[0]+(b?-1:1)*S(n)*(f[2]/2+p)};this.center=f;l(q,function(b){a+=b.y});l(q,function(c){t=a?c.y/a:0;j=z(b*x*1E3)/1E3;b+=t;m=z(b*x*1E3)/1E3;c.shapeType="arc";c.shapeArgs=
{x:f[0],y:f[1],r:f[2]/2,innerR:f[3]/2,start:j,end:m};n=(m+j)/2;c.slicedTranslation=qb([S(n)*d+g.plotLeft,ma(n)*d+g.plotTop],z);o=S(n)*f[2]/2;A=ma(n)*f[2]/2;c.tooltipPos=[f[0]+o*0.7,f[1]+A*0.7];c.labelPos=[f[0]+o+S(n)*p,f[1]+A+ma(n)*p,f[0]+o+S(n)*e,f[1]+A+ma(n)*e,f[0]+o,f[1]+A,p<0?"center":n<x/4?"left":"right",n];c.percentage=t*100;c.total=a});this.setTooltipPoints()},render:function(){this.drawPoints();this.options.enableMouseTracking!==!1&&this.drawTracker();this.drawDataLabels();this.options.animation&&
this.animate&&this.animate();this.isDirty=!1},drawPoints:function(){var a=this.chart,b=a.renderer,c,d,e,f=this.options.shadow,g,h;l(this.data,function(i){d=i.graphic;h=i.shapeArgs;e=i.group;g=i.shadowGroup;if(f&&!g)g=i.shadowGroup=b.g("shadow").attr({zIndex:4}).add();if(!e)e=i.group=b.g("point").attr({zIndex:5}).add();c=i.sliced?i.slicedTranslation:[a.plotLeft,a.plotTop];e.translate(c[0],c[1]);g&&g.translate(c[0],c[1]);d?d.animate(h):i.graphic=b.arc(h).attr(E(i.pointAttr[pa],{"stroke-linejoin":"round"})).add(i.group).shadow(f,
g);i.visible===!1&&i.setVisible(!1)})},drawDataLabels:function(){var a=this.data,b,c=this.chart,d=this.options.dataLabels,e=n(d.connectorPadding,10),f=n(d.connectorWidth,1),g,h,i=n(d.softConnector,!0),j=d.distance,m=this.center,q=m[2]/2,m=m[1],z=j>0,x=[[],[]],t,r,y,o,A=2,p;if(d.enabled){ba.prototype.drawDataLabels.apply(this);l(a,function(a){a.dataLabel&&x[a.labelPos[7]<qa/2?0:1].push(a)});x[1].reverse();o=function(a,b){return b.y-a.y};for(a=x[0][0]&&x[0][0].dataLabel&&K(x[0][0].dataLabel.styles.lineHeight);A--;){var u=
[],G=[],E=x[A],F=E.length,C;for(p=m-q-j;p<=m+q+j;p+=a)u.push(p);y=u.length;if(F>y){h=[].concat(E);h.sort(o);for(p=F;p--;)h[p].rank=p;for(p=F;p--;)E[p].rank>=y&&E.splice(p,1);F=E.length}for(p=0;p<F;p++){b=E[p];h=b.labelPos;b=9999;for(r=0;r<y;r++)g=ya(u[r]-h[1]),g<b&&(b=g,C=r);if(C<p&&u[p]!==null)C=p;else for(y<F-p+C&&u[p]!==null&&(C=y-F+p);u[C]===null;)C++;G.push({i:C,y:u[C]});u[C]=null}G.sort(o);for(p=0;p<F;p++){b=E[p];h=b.labelPos;g=b.dataLabel;r=G.pop();t=h[1];y=b.visible===!1?Ja:Pa;C=r.i;r=r.y;
if(t>r&&u[C+1]!==null||t<r&&u[C-1]!==null)r=t;t=this.getX(C===0||C===u.length-1?t:r,A);g.attr({visibility:y,align:h[6]})[g.moved?"animate":"attr"]({x:t+d.x+({left:e,right:-e}[h[6]]||0),y:r+d.y});g.moved=!0;if(z&&f)g=b.connector,h=i?[va,t+(h[6]==="left"?5:-5),r,"C",t,r,2*h[2]-h[4],2*h[3]-h[5],h[2],h[3],aa,h[4],h[5]]:[va,t+(h[6]==="left"?5:-5),r,aa,h[2],h[3],aa,h[4],h[5]],g?(g.animate({d:h}),g.attr("visibility",y)):b.connector=g=this.chart.renderer.path(h).attr({"stroke-width":f,stroke:d.connectorColor||
b.color||"#606060",visibility:y,zIndex:3}).translate(c.plotLeft,c.plotTop).add()}}}},drawTracker:cb.prototype.drawTracker,getSymbol:function(){}});la.pie=y;ka.Highcharts={Chart:yb,dateFormat:Ob,pathAnim:Ba,getOptions:function(){return sa},hasRtlBug:Dc,numberFormat:mc,Point:Xa,Color:Fa,Renderer:Sb,seriesTypes:la,setOptions:function(a){sa=Q(sa,a);wb();return sa},Series:ba,addEvent:ha,createElement:W,discardElement:Lb,css:C,each:l,extend:E,map:qb,merge:Q,pick:n,extendClass:ca,product:"Highcharts",version:"2.1.7"}})();

﻿var AVIMGlobalConfig = {
	method: 0, //Default input method: 0=AUTO, 1=TELEX, 2=VNI, 3=VIQR, 4=VIQR*
	onOff: 0, //Starting status: 0=Off, 1=On
	ckSpell: 1, //Spell Check: 0=Off, 1=On
	oldAccent: 1, //0: New way (oa`, oe`, uy`), 1: The good old day (o`a, o`e, u`y)
	useCookie: 1, //Cookies: 0=Off, 1=On
	exclude: ["email"], //IDs of the fields you DON'T want to let users type Vietnamese in
	showControl: 1, //Show control panel: 0=Off, 1=On. If you turn this off, you must write your own control panel.
	controlCSS: "resource/css/avim.css" //Path to avim.css
};

//Set to true the methods which you want to be included in the AUTO method
var AVIMAutoConfig = {
	telex: true,
	vni: true,
	viqr: false,
	viqrStar: false
};

function AVIM()	{
	this.radioID = "avim_auto,avim_telex,avim_vni,avim_viqr,avim_viqr2,avim_off,avim_ckspell,avim_daucu".split(",");
	this.attached = [];
	this.changed = false;
	this.agt = navigator.userAgent.toLowerCase();
	this.alphabet = "QWERTYUIOPASDFGHJKLZXCVBNM\ ";
	this.support = true;
	this.ver = 0;
	this.specialChange = false;
	this.is_ie = ((this.agt.indexOf("msie") != -1) && (this.agt.indexOf("opera") == -1));
	this.is_opera = false;
	this.isKHTML = false;
	this.kl = 0;
	this.skey = [97,226,259,101,234,105,111,244,417,117,432,121,65,194,258,69,202,73,79,212,416,85,431,89];
	this.fID = document.getElementsByTagName("iframe");
	this.range = null;
	this.whit = false;
	this.db1 = [273,272];
	this.ds1 = ['d','D'];
	this.os1 = "o,O,ơ,Ơ,ó,Ó,ò,Ò,ọ,Ọ,ỏ,Ỏ,õ,Õ,ớ,Ớ,ờ,Ờ,ợ,Ợ,ở,Ở,ỡ,Ỡ".split(",");
	this.ob1 = "ô,Ô,ô,Ô,ố,Ố,ồ,Ồ,ộ,Ộ,ổ,Ổ,ỗ,Ỗ,ố,Ố,ồ,Ồ,ộ,Ộ,ổ,Ổ,ỗ,Ỗ".split(",");
	this.mocs1 = "o,O,ô,Ô,u,U,ó,Ó,ò,Ò,ọ,Ọ,ỏ,Ỏ,õ,Õ,ú,Ú,ù,Ù,ụ,Ụ,ủ,Ủ,ũ,Ũ,ố,Ố,ồ,Ồ,ộ,Ộ,ổ,Ổ,ỗ,Ỗ".split(",");
	this.mocb1 = "ơ,Ơ,ơ,Ơ,ư,Ư,ớ,Ớ,ờ,Ờ,ợ,Ợ,ở,Ở,ỡ,Ỡ,ứ,Ứ,ừ,Ừ,ự,Ự,ử,Ử,ữ,Ữ,ớ,Ớ,ờ,Ờ,ợ,Ợ,ở,Ở,ỡ,Ỡ".split(",");
	this.trangs1 = "a,A,â,Â,á,Á,à,À,ạ,Ạ,ả,Ả,ã,Ã,ấ,Ấ,ầ,Ầ,ậ,Ậ,ẩ,Ẩ,ẫ,Ẫ".split(",");
	this.trangb1 = "ă,Ă,ă,Ă,ắ,Ắ,ằ,Ằ,ặ,Ặ,ẳ,Ẳ,ẵ,Ẵ,ắ,Ắ,ằ,Ằ,ặ,Ặ,ẳ,Ẳ,ẵ,Ẵ".split(",");
	this.as1 = "a,A,ă,Ă,á,Á,à,À,ạ,Ạ,ả,Ả,ã,Ã,ắ,Ắ,ằ,Ằ,ặ,Ặ,ẳ,Ẳ,ẵ,Ẵ,ế,Ế,ề,Ề,ệ,Ệ,ể,Ể,ễ,Ễ".split(",");
	this.ab1 = "â,Â,â,Â,ấ,Ấ,ầ,Ầ,ậ,Ậ,ẩ,Ẩ,ẫ,Ẫ,ấ,Ấ,ầ,Ầ,ậ,Ậ,ẩ,Ẩ,ẫ,Ẫ,é,É,è,È,ẹ,Ẹ,ẻ,Ẻ,ẽ,Ẽ".split(",");
	this.es1 = "e,E,é,É,è,È,ẹ,Ẹ,ẻ,Ẻ,ẽ,Ẽ".split(",");
	this.eb1 = "ê,Ê,ế,Ế,ề,Ề,ệ,Ệ,ể,Ể,ễ,Ễ".split(",");
	this.english = "ĐÂĂƠƯÊÔ";
	this.lowen = "đâăơưêô";
	this.arA = "á,à,ả,ã,ạ,a,Á,À,Ả,Ã,Ạ,A".split(',');
	this.mocrA = "ó,ò,ỏ,õ,ọ,o,ú,ù,ủ,ũ,ụ,u,Ó,Ò,Ỏ,Õ,Ọ,O,Ú,Ù,Ủ,Ũ,Ụ,U".split(',');
	this.erA = "é,è,ẻ,ẽ,ẹ,e,É,È,Ẻ,Ẽ,Ẹ,E".split(',');
	this.orA = "ó,ò,ỏ,õ,ọ,o,Ó,Ò,Ỏ,Õ,Ọ,O".split(',');
	this.aA = "ấ,ầ,ẩ,ẫ,ậ,â,Ấ,Ầ,Ẩ,Ẫ,Ậ,Â".split(',');
	this.oA = "ố,ồ,ổ,ỗ,ộ,ô,Ố,Ồ,Ổ,Ỗ,Ộ,Ô".split(',');
	this.mocA = "ớ,ờ,ở,ỡ,ợ,ơ,ứ,ừ,ử,ữ,ự,ư,Ớ,Ờ,Ở,Ỡ,Ợ,Ơ,Ứ,Ừ,Ử,Ữ,Ự,Ư".split(',');
	this.trangA = "ắ,ằ,ẳ,ẵ,ặ,ă,Ắ,Ằ,Ẳ,Ẵ,Ặ,Ă".split(',');
	this.eA = "ế,ề,ể,ễ,ệ,ê,Ế,Ề,Ể,Ễ,Ệ,Ê".split(',');
	this.oA = "ố,ồ,ổ,ỗ,ộ,ô,Ố,Ồ,Ổ,Ỗ,Ộ,Ô".split(',');
	this.skey2 = "a,a,a,e,e,i,o,o,o,u,u,y,A,A,A,E,E,I,O,O,O,U,U,Y".split(',');
	
	this.fcc = function(x) {
		return String.fromCharCode(x);
	}
	
	this.getEL = function(id) {
		return document.getElementById(id);
	}
	
	this.getSF = function() {
		var sf = [], x;
		for(x = 0; x < this.skey.length; x++) {
			sf[sf.length] = this.fcc(this.skey[x]);
		}
		return sf;
	}
	
	if(AVIMGlobalConfig.showControl) {
		this.css = document.createElement('link');
		this.css.rel = 'stylesheet';
		this.css.type = 'text/css';
		this.css.href = AVIMGlobalConfig.controlCSS;
		document.getElementsByTagName('head')[0].appendChild(this.css);

		var str = "";
		str+=('<div id="AVIMControl-Button" class="AVIMControl"><input id="avim_auto" type="radio" name="AVIMMethod" onclick="AVIMObj.setMethod(0);" />Tự động');
		str+=('<input id="avim_telex" type="radio" name="AVIMMethod" onclick="AVIMObj.setMethod(1);" />TELEX');
		str+=('<input id="avim_vni" type="radio" name="AVIMMethod" onclick="AVIMObj.setMethod(2);" />VNI');
		str+=('<input id="avim_viqr" type="radio" name="AVIMMethod" onclick="AVIMObj.setMethod(3);" />VIQR');
		str+=('<input id="avim_viqr2" type="radio" name="AVIMMethod" onclick="AVIMObj.setMethod(4);" />VIQR*');
		str+=('<input id="avim_off" type="radio" name="AVIMMethod" onclick="AVIMObj.setMethod(-1);" />Tắt<br />');
		str+=('<input type="checkbox" id="avim_ckspell" onclick="AVIMObj.setSpell(this);" />Chính tả');
		str+=('<input type="checkbox" id="avim_daucu" onclick="AVIMObj.setDauCu(this);" />Kiểu cũ</div>');
		str+=('<a class="AVIMControl" style="float: right; position: relative; top: 3px;" onclick="$('+"'#AVIMControl-Button'"+').slideToggle();"' + '">[Bât/Ẩn bộ gõ]</a>');
		document.getElementById("AVIMControl").innerHTML = str;
		//document.write(str);
	}

	if(!this.is_ie) {
		if(this.agt.indexOf("opera") >= 0) {
			this.operaV = this.agt.split(" ");
			this.operaVersion = parseInt(this.operaV[this.operaV.length - 1]);
			if(this.operaVersion >= 8) {
				this.is_opera = true;
			} else {
				this.operaV = this.operaV[0].split("/");
				this.operaVersion = parseInt(this.operaV[1]);
				if(this.operaVersion >= 8) this.is_opera = true;
			}
		} else if(this.agt.indexOf("khtml") >= 0) {
			this.isKHTML = true;
		} else {
			this.ver = this.agt.substr(this.agt.indexOf("rv:") + 3);
			this.ver = parseFloat(this.ver.substr(0, this.ver.indexOf(" ")));
			if(this.agt.indexOf("mozilla") < 0) this.ver = 0;
		}
	}
	
	this.nospell = function(w, k) {
		return false;
	}
	
	this.ckspell = function(w, k) {
		w = this.unV(w);
		var exc = "UOU,IEU".split(','), z, next = true, noE = "UU,UOU,UOI,IEU,AO,IA,AI,AY,AU,AO".split(','), noBE = "YEU";
		var check = true, noM = "UE,UYE,IU,EU,UY".split(','), noMT = "AY,AU".split(','), noT = "UA", t = -1, notV2 = "IAO";
		var uw = this.up(w), tw = uw, update = false, gi = "IO", noAOEW = "OE,OO,AO,EO,IA,AI".split(','), noAOE = "OA", test, a, b;
		var notViet = "AA,AE,EE,OU,YY,YI,IY,EY,EA,EI,II,IO,YO,YA,OOO".split(','), uk = this.up(k), twE, uw2 = this.unV2(uw);
		var vSConsonant = "B,C,D,G,H,K,L,M,N,P,Q,R,S,T,V,X".split(','), vDConsonant = "CH,GI,KH,NGH,GH,NG,NH,PH,QU,TH,TR".split(',');
		var vDConsonantE = "CH,NG,NH".split(','),sConsonant = "C,P,T,CH".split(','),vSConsonantE = "C,M,N,P,T".split(',');
		var noNHE = "O,U,IE,Ô,Ơ,Ư,IÊ,Ă,Â,UYE,UYÊ,UO,ƯƠ,ƯO,UƠ,UA,ƯA,OĂ,OE,OÊ".split(','),oMoc = "UU,UOU".split(',');
		if(this.FRX.indexOf(uk) >= 0) {
			for(a = 0; a < sConsonant.length; a++) {
				if(uw.substr(uw.length - sConsonant[a].length, sConsonant[a].length) == sConsonant[a]) {
					return true;
				}
			}
		}
		for(a = 0; a < uw.length; a++) {
			if("FJZW1234567890".indexOf(uw.substr(a, 1)) >= 0) {
				return true;
			}
			for(b = 0; b < notViet.length; b++) {
				if(uw2.substr(a, notViet[b].length) == notViet[b]) {
					for(z = 0; z < exc.length; z++) {
						if(uw2.indexOf(exc[z]) >= 0) {
							next=false;
						}
					}
					if(next && ((gi.indexOf(notViet[b]) < 0) || (a <= 0) || (uw2.substr(a - 1, 1) != 'G'))) {
						return true;
					}
				}
			}
		}
		for(b = 0; b < vDConsonant.length; b++) {
			if(tw.indexOf(vDConsonant[b]) == 0) {
				tw = tw.substr(vDConsonant[b].length);
				update = true;
				t = b;
				break;
			}
		}
		if(!update) {
			for(b = 0; b < vSConsonant.length; b++) {
				if(tw.indexOf(vSConsonant[b]) == 0) {
					tw=tw.substr(1);
					break;
				}
			}
		}
		update=false;
		twE=tw;
		for(b = 0; b < vDConsonantE.length; b++) {
			if(tw.substr(tw.length - vDConsonantE[b].length) == vDConsonantE[b]) {
				tw = tw.substr(0, tw.length - vDConsonantE[b].length);
				if(b == 2){
					for(z = 0; z < noNHE.length; z++) {
						if(tw == noNHE[z]) {
							return true;
						}
					}
					if((uk == this.trang) && ((tw == "OA") || (tw == "A"))) {
						return true;
					}
				}
				update = true;
				break;
			}
		}
		if(!update) {
			for(b = 0; b < vSConsonantE.length; b++) {
				if(tw.substr(tw.length - 1) == vSConsonantE[b]) {
					tw = tw.substr(0, tw.length - 1);
					break;
				}
			}
		}
		if(tw) {
			for(a = 0; a < vDConsonant.length; a++) {
				for(b = 0; b < tw.length; b++) {
					if(tw.substr(b, vDConsonant[a].length) == vDConsonant[a]) {
						return true;
					}
				}
			}
			for(a = 0; a < vSConsonant.length; a++) {
				if(tw.indexOf(vSConsonant[a]) >= 0) {
					return true;
				}
			}
		}
		test = tw.substr(0, 1);
		if((t == 3) && ((test == "A") || (test == "O") || (test == "U") || (test == "Y"))) {
			return true;
		}
		if((t == 5) && ((test == "E") || (test == "I") || (test == "Y"))) {
			return true;
		}
		uw2 = this.unV2(tw);
		if(uw2 == notV2) {
			return true;
		}
		if(tw != twE) {
			for(z = 0; z < noE.length; z++) {
				if(uw2 == noE[z]) {
					return true;
				}
			}
		}
		if((tw != uw) && (uw2 == noBE)) {
			return true;
		}
		if(uk != this.moc) {
			for(z = 0; z < oMoc.length; z++) {
				if(tw == oMoc[z]) return true;
			}
		}
		if((uw2.indexOf('UYE')>0) && (uk == 'E')) {
			check=false;
		}
		if((this.them.indexOf(uk) >= 0) && check) {
			for(a = 0; a < noAOEW.length; a++) {
				if(uw2.indexOf(noAOEW[a]) >= 0) {
					return true;
				}
			}
			if(uk != this.trang) {
				if(uw2 == noAOE) {
					return true;
				}
			}
			if((uk == this.trang) && (this.trang != 'W')) {
				if(uw2 == noT) {
					return true;
				}
			}
			if(uk == this.moc) {
				for(a = 0; a < noM.length; a++) {
					if(uw2 == noM[a]) {
						return true;
					}
				}
			}
			if((uk == this.moc) || (uk == this.trang)) {
				for(a = 0; a < noMT.length; a++) {
					if(uw2 == noMT[a]) {
						return true;
					}
				}
			}
		}
		this.tw5 = tw;
		if((uw2.charCodeAt(0) == 272) || (uw2.charCodeAt(0) == 273)) {
			if(uw2.length > 4) {
				return true;
			}
		} else if(uw2.length > 3) {
			return true;
		}
		return false;
	}
	
	this.noCookie = function() {}
	
	this.doSetCookie = function() {
		var exp = new Date(11245711156480).toGMTString();
		document.cookie = 'AVIM_on_off=' + AVIMGlobalConfig.onOff + ';expires=' + exp;
		document.cookie = 'AVIM_method=' + AVIMGlobalConfig.method + ';expires=' + exp;
		document.cookie = 'AVIM_ckspell=' + AVIMGlobalConfig.ckSpell + ';expires=' + exp;
		document.cookie = 'AVIM_daucu=' + AVIMGlobalConfig.oldAccent + ';expires=' + exp;
	}
	
	this.doGetCookie = function() {
		var ck = document.cookie, res = /AVIM_method/.test(ck), p, i, ckA = ck.split(';');
		if(!res || (ck.indexOf('AVIM_ckspell') < 0)) {
			this.setCookie();
			return;
		}
		for(i = 0; i < ckA.length; i++) {
			p = ckA[i].split('=');
			p[0] = p[0].replace(/^\s+/g, "");
			p[1] = parseInt(p[1]);
			if(p[0] == 'AVIM_on_off') {
				AVIMGlobalConfig.onOff = p[1];
			}
			else if(p[0] == 'AVIM_method') {
				AVIMGlobalConfig.method = p[1];
			}
			else if(p[0] == 'AVIM_ckspell') {
				if(p[1] == 0) {
					AVIMGlobalConfig.ckSpell=0;
					this.spellerr=this.nospell;
				} else {
					AVIMGlobalConfig.ckSpell=1;
					this.spellerr=this.ckspell;
				}
			} else if(p[0] == 'AVIM_daucu') {
				AVIMGlobalConfig.oldAccent = parseInt(p[1]);
			}
		}
	}
	
	if(AVIMGlobalConfig.useCookie == 1) {
		this.setCookie = this.doSetCookie;
		this.getCookie = this.doGetCookie;
	} else {
		this.setCookie = this.noCookie;
		this.getCookie = this.noCookie;
	}
	
	this.setMethod = function(m) {
		if(m == -1) {
			AVIMGlobalConfig.onOff = 0;
			if(this.getEL(this.radioID[5])) {
				this.getEL(this.radioID[5]).checked = true;
			}
		} else {
			AVIMGlobalConfig.onOff = 1;
			AVIMGlobalConfig.method = m;
			if(this.getEL(this.radioID[m])) {
				this.getEL(this.radioID[m]).checked = true;
			}
		}
		this.setSpell(AVIMGlobalConfig.ckSpell);
		this.setDauCu(AVIMGlobalConfig.oldAccent);
		this.setCookie();
	}
	
	this.setDauCu = function(box) {
		if(typeof(box) == "number") {
			AVIMGlobalConfig.oldAccent = box;
			if(this.getEL(this.radioID[7])) {
				this.getEL(this.radioID[7]).checked = box;
			}
		} else {
			AVIMGlobalConfig.oldAccent = (box.checked) ? 1 : 0;
		}
		this.setCookie();
	}
	
	this.setSpell = function(box) {
		if(typeof(box) == "number") {
			this.spellerr = (box == 1) ? this.ckspell : this.nospell;
			if(this.getEL(this.radioID[6])) {
				this.getEL(this.radioID[6]).checked = box;
			}
		} else {
			if(box.checked) {
				this.spellerr = this.ckspell;
				AVIMGlobalConfig.ckSpell = 1;
			} else {
				this.spellerr = this.nospell;
				AVIMGlobalConfig.ckSpell = 0;
			}
		}
		this.setCookie();
	}
	
	if(this.is_ie || (this.ver >= 1.3) || this.is_opera || this.isKHTML) {
		this.getCookie();
		if(AVIMGlobalConfig.onOff == 0) this.setMethod(-1);
		else this.setMethod(AVIMGlobalConfig.method);
		this.setSpell(AVIMGlobalConfig.ckSpell);
		this.setDauCu(AVIMGlobalConfig.oldAccent);
	} else {
		//this.support = false;
	}
	
	this.mozGetText = function(obj) {
		var v, pos, w = "", g = 1;
		v = (obj.data) ? obj.data : obj.value;
		if(v.length <= 0) {
			return false;
		}
		if(!obj.data) {
			if(!obj.setSelectionRange) {
				return false;
			}
			pos = obj.selectionStart;
		} else {
			pos = obj.pos;
		}
		if(obj.selectionStart != obj.selectionEnd) {
			return ["", pos];
		}
		while(1) {
			if(pos - g < 0) {
				break;
			} else if(this.notWord(v.substr(pos - g, 1))) {
				if(v.substr(pos - g, 1) == "\\") {
					w = v.substr(pos - g, 1) + w;
				}
				break;
			} else {
				w = v.substr(pos - g, 1) + w;
			}
			g++;
		}
		return [w, pos];
	}
	
	this.ieGetText = function(obj) {
		var caret = obj.document.selection.createRange(), w="";
		if(caret.text) {
			caret.text = "";
		} else {
			while(1) {
				caret.moveStart("character", -1);
				if(w.length == caret.text.length) {
					break;
				}
				w = caret.text;
				if(this.notWord(w.charAt(0))) {
					if(w.charCodeAt(0) == 13) {
						w=w.substr(2);
					} else if(w.charAt(0) != "\\") {
						w=w.substr(1);
					}
					break;
				}
			}
		}
		if(w.length) {
			caret.collapse(false);
			caret.moveStart("character", -w.length);
			obj.cW = caret.duplicate();
			return obj;
		} else {
			return false;
		}
	}
	
	this.start = function(obj, key) {
		var w = "", method = AVIMGlobalConfig.method, dockspell = AVIMGlobalConfig.ckSpell, uni, uni2 = false, uni3 = false, uni4 = false;
		this.oc=obj;
		var telex = "D,A,E,O,W,W".split(','), vni = "9,6,6,6,7,8".split(','), viqr = "D,^,^,^,+,(".split(','), viqr2 = "D,^,^,^,*,(".split(','), a, noNormC;
		if(method == 0) {
			var arr = [], check = [AVIMAutoConfig.telex, AVIMAutoConfig.vni, AVIMAutoConfig.viqr, AVIMAutoConfig.viqrStar];
			var value1 = [telex, vni, viqr, viqr2], uniA = [uni, uni2, uni3, uni4], D2A = ["DAWEO", "6789", "D^+(", "D^*("];
			for(a = 0; a < check.length; a++) {
				if(check[a]) {
					arr[arr.length] = value1[a];
				} else {
					D2A[a] = "";
				}
			}
			for(a = 0; a < arr.length; a++) {
				uniA[a] = arr[a];
			}
			uni = uniA[0];
			uni2 = uniA[1];
			uni3 = uniA[2];
			uni4 = uniA[3];
			this.D2 = D2A.join();
			if(!uni) {
				return;
			}
		} else if(method == 1) {
			uni = telex;
			this.D2 = "DAWEO";
		}
		else if(method == 2) {
			uni = vni;
			this.D2 = "6789";
		}
		else if(method == 3) {
			uni = viqr;
			this.D2 = "D^+(";
		}
		else if(method == 4) {
			uni = viqr2;
			this.D2 = "D^*(";
		}
		if(!this.is_ie) {
			key = this.fcc(key.which);
			w = this.mozGetText(obj);
			if(!w || obj.sel) {
				return;
			}
			if(this.D2.indexOf(this.up(key)) >= 0) {
				noNormC = true;
			} else {
				noNormC = false;
			}
			this.main(w[0], key, w[1], uni, noNormC);
			if(!dockspell) {
				w = this.mozGetText(obj);
			}
			if(w && uni2 && !this.changed) {
				this.main(w[0], key, w[1], uni2, noNormC);
			}
			if(!dockspell) {
				w = this.mozGetText(obj);
			}
			if(w && uni3 && !this.changed) {
				this.main(w[0], key, w[1], uni3, noNormC);
			}
			if(!dockspell) {
				w = this.mozGetText(obj);
			}
			if(w && uni4 && !this.changed) {
				this.main(w[0], key, w[1], uni4, noNormC);
			}
		} else {
			obj = this.ieGetText(obj);
			if(obj) {
				var sT = obj.cW.text;
				w = this.main(sT, key, 0, uni, false);
				if(uni2 && ((w == sT) || (typeof(w) == 'undefined'))) {
					w = this.main(sT, key, 0, uni2, false);
				}
				if(uni3 && ((w == sT) || (typeof(w) == 'undefined'))) {
					w = this.main(sT, key, 0, uni3, false);
				}
				if(uni4 && ((w == sT) || (typeof(w) == 'undefined'))) {
					w = this.main(sT, key, 0, uni4, false);
				}
				if(w) {
					obj.cW.text = w;
				}
			}
		}
		if(this.D2.indexOf(this.up(key)) >= 0) {
			if(!this.is_ie) {
				w = this.mozGetText(obj);
				if(!w) {
					return;
				}
				this.normC(w[0], key, w[1]);
			} else if(typeof(obj) == "object") {
				obj = this.ieGetText(obj);
				if(obj) {
					w = obj.cW.text;
					if(!this.changed) {
						w += key;
						this.changed = true;
					}
					obj.cW.text = w;
					w = this.normC(w, key, 0);
					if(w) {
						obj = this.ieGetText(obj);
						obj.cW.text = w;
					}
				}
			}
		}
	}
	
	this.findC = function(w, k, sf) {
		var method = AVIMGlobalConfig.method;
		if(((method == 3) || (method == 4)) && (w.substr(w.length - 1, 1) == "\\")) {
			return [1, k.charCodeAt(0)];
		}
		var str = "", res, cc = "", pc = "", tE = "", vowA = [], s = "ÂĂÊÔƠƯêâăơôư", c = 0, dn = false, uw = this.up(w), tv, g;
		var DAWEOFA = this.up(this.aA.join() + this.eA.join() + this.mocA.join() + this.trangA.join() + this.oA.join() + this.english), h, uc;
		for(g = 0; g < sf.length; g++) {
			if(this.nan(sf[g])) {
				str += sf[g];
			} else {
				str += this.fcc(sf[g]);
			}
		}
		var uk = this.up(k), uni_array = this.repSign(k), w2 = this.up(this.unV2(this.unV(w))), dont = "ƯA,ƯU".split(',');
		if (this.DAWEO.indexOf(uk) >= 0) {
			if(uk == this.moc) {
				if((w2.indexOf("UU") >= 0) && (this.tw5 != dont[1])) {
					if(w2.indexOf("UU") == (w.length - 2)) {
						res=2;
					} else {
						return false;
					}
				} else if(w2.indexOf("UOU") >= 0) {
					if(w2.indexOf("UOU") == (w.length-3)) {
						res=2;
					} else {
						return false;
					}
				}
			}
			if(!res) {
				for(g = 1; g <= w.length; g++) {
					cc = w.substr(w.length - g, 1);
					pc = this.up(w.substr(w.length - g - 1, 1));
					uc = this.up(cc);
					for(h = 0; h < dont.length; h++) {
						if((this.tw5 == dont[h]) && (this.tw5 == this.unV(pc + uc))) {
							dn = true;
						}
					}
					if(dn) {
						dn = false;
						continue;
					}
					if(str.indexOf(uc) >= 0) {
						if(((uk == this.moc) && (this.unV(uc) == "U") && (this.up(this.unV(w.substr(w.length - g + 1, 1))) == "A")) || ((uk == this.trang) && (this.unV(uc) == 'A') && (this.unV(pc) == 'U'))) {
							if(this.unV(uc) == "U") {
								tv=1;
							} else {
								tv=2;
							}
							var ccc = this.up(w.substr(w.length - g - tv, 1));
							if(ccc != "Q") {
								res = g + tv - 1;
							} else if(uk == this.trang) {
								res = g;
							} else if(this.moc != this.trang) {
								return false;
							}
						} else {
							res = g;
						}
						if(!this.whit || (uw.indexOf("Ư") < 0) || (uw.indexOf("W") < 0)) {
							break;
						}
					} else if(DAWEOFA.indexOf(uc) >= 0) {
						if(uk == this.D) {
							if(cc == "đ") {
								res = [g, 'd'];
							} else if(cc == "Đ") {
								res = [g, 'D'];
							}
						} else {
							res = this.DAWEOF(cc, uk, g);
						}
						if(res) break;
					}
				}
			}
		}
		if((uk != this.Z) && (this.DAWEO.indexOf(uk) < 0)) {
			var tEC = this.retKC(uk);
			for(g = 0;g < tEC.length; g++) {
				tE += this.fcc(tEC[g]);
			}
		}
		for(g = 1; g <= w.length; g++) {
			if(this.DAWEO.indexOf(uk) < 0) {
				cc = this.up(w.substr(w.length - g, 1));
				pc = this.up(w.substr(w.length - g - 1, 1));
				if(str.indexOf(cc) >= 0) {
					if(cc == 'U') {
						if(pc != 'Q') {
							c++;
							vowA[vowA.length] = g;
						}
					} else if(cc == 'I') {
						if((pc != 'G') || (c <= 0)) {
							c++;
							vowA[vowA.length] = g;
						}
					} else {
						c++;
						vowA[vowA.length] = g;
					}
				} else if(uk != this.Z) {
					for(h = 0; h < uni_array.length; h++) if(uni_array[h] == w.charCodeAt(w.length - g)) {
						if(this.spellerr(w, k)) {
							return false;
						}
						return [g, tEC[h % 24]];
					}
					for(h = 0; h < tEC.length; h++) {
						if(tEC[h] == w.charCodeAt(w.length - g)) {
							return [g, this.fcc(this.skey[h])];
						}
					}
				}
			}
		}
		if((uk != this.Z) && (typeof(res) != 'object')) {
			if(this.spellerr(w, k)) {
				return false;
			}
		}
		if(this.DAWEO.indexOf(uk) < 0) {
			for(g = 1; g <= w.length; g++) {
				if((uk != this.Z) && (s.indexOf(w.substr(w.length - g, 1)) >= 0)) {
					return g;
				} else if(tE.indexOf(w.substr(w.length - g, 1)) >= 0) {
					for(h = 0; h < tEC.length; h++) {
						if(w.substr(w.length - g, 1).charCodeAt(0) == tEC[h]) {
							return [g, this.fcc(this.skey[h])];
						}
					}
				}
			}
		}
		if(res) {
			return res;
		}
		if((c == 1) || (uk == this.Z)) {
			return vowA[0];
		} else if(c == 2) {
			var v = 2;
			if(w.substr(w.length - 1) == " ") {
				v = 3;
			}
			var ttt = this.up(w.substr(w.length - v, 2));
			if((AVIMGlobalConfig.oldAccent == 0) && ((ttt == "UY") || (ttt == "OA") || (ttt == "OE"))) {
				return vowA[0];
			}
			var c2 = 0, fdconsonant, sc = "BCD" + this.fcc(272) + "GHKLMNPQRSTVX", dc = "CH,GI,KH,NGH,GH,NG,NH,PH,QU,TH,TR".split(',');
			for(h = 1; h <= w.length; h++) {
				fdconsonant=false;
				for(g = 0; g < dc.length; g++) {
					if(this.up(w.substr(w.length - h - dc[g].length + 1, dc[g].length)).indexOf(dc[g])>=0) {
						c2++;
						fdconsonant = true;
						if(dc[g] != 'NGH') {
							h++;
						} else {
							h+=2;
						}
					}
				}
				if(!fdconsonant) {
					if(sc.indexOf(this.up(w.substr(w.length - h, 1))) >= 0) {
						c2++;
					} else { 
						break;
					}
				}
			}
			if((c2 == 1) || (c2 == 2)) {
				return vowA[0];
			} else {
				return vowA[1];
			}
		} else if(c == 3) {
			return vowA[1];
		} else return false;
	}
	
	this.ie_replaceChar = function(w, pos, c) {
		var r = "", uc = 0;
		if(isNaN(c)) uc = this.up(c);
		if(this.whit && (this.up(w.substr(w.length - pos - 1, 1)) == 'U') && (pos != 1) && (this.up(w.substr(w.length - pos - 2, 1)) != 'Q')) {
			this.whit = false;
			if((this.up(this.unV(this.fcc(c))) == "Ơ") || (uc == "O")) {
				if(w.substr(w.length - pos - 1, 1) == 'u') r = this.fcc(432);
				else r = this.fcc(431);
			}
			if(uc == "O") {
				if(c == "o") {
					c = 417;
				} else {
					c = 416;
				}
			}
		}
		if(!isNaN(c)) {
			this.changed = true;
			r += this.fcc(c);
			return w.substr(0, w.length - pos - r.length + 1) + r + w.substr(w.length - pos + 1);
		} else {
			return w.substr(0, w.length - pos) + c + w.substr(w.length - pos + 1);
		}
	}
	
	this.replaceChar = function(o, pos, c) {
		var bb = false;
		if(!this.nan(c)) {
			var replaceBy = this.fcc(c), wfix = this.up(this.unV(this.fcc(c)));
			this.changed = true;
		} else {
			var replaceBy = c;
			if((this.up(c) == "O") && this.whit) {
				bb=true;
			}
		}
		if(!o.data) {
			var savePos = o.selectionStart, sst = o.scrollTop;
			if ((this.up(o.value.substr(pos - 1, 1)) == 'U') && (pos < savePos - 1) && (this.up(o.value.substr(pos - 2, 1)) != 'Q')) {
				if((wfix == "Ơ") || bb) {
					if (o.value.substr(pos-1,1) == 'u') {
						var r = this.fcc(432);
					} else {
						var r = this.fcc(431);
					}
				}
				if(bb) {
					this.changed = true;
					if(c == "o") {
						replaceBy = "ơ";
					} else {
						replaceBy = "Ơ";
					}
				}
			}
			o.value = o.value.substr(0, pos) + replaceBy + o.value.substr(pos + 1);
			if(r) o.value = o.value.substr(0, pos - 1) + r + o.value.substr(pos);
			//o.setSelectionRange(savePos, savePos);
			o.scrollTop = sst;
		} else {
			if ((this.up(o.data.substr(pos - 1, 1)) == 'U') && (pos < o.pos - 1)) {
				if((wfix == "Ơ") || bb) {
					if (o.data.substr(pos - 1, 1) == 'u') {
						var r = this.fcc(432);
					} else {
						var r = this.fcc(431);
					}
				}
				if(bb) {
					this.changed = true;
					if(c == "o") {
						replaceBy = "ơ";
					} else {
						replaceBy = "Ơ";
					}
				}
			}
			o.deleteData(pos, 1);
			o.insertData(pos, replaceBy);
			if(r) {
				o.deleteData(pos - 1, 1);
				o.insertData(pos - 1, r);
			}
		}
		if(this.whit) {
			this.whit=false;
		}
	}
	
	this.tr = function(k, w, by, sf, i) {
		var r, pos = this.findC(w, k, sf), g;
		if(pos) {
			if(pos[1]) {
				if(this.is_ie) {
					return this.ie_replaceChar(w, pos[0], pos[1]);
				} else {
					return this.replaceChar(this.oc, i-pos[0], pos[1]);
				}
			} else {
				var c, pC = w.substr(w.length - pos, 1), cmp;
				r = sf;
				for(g = 0; g < r.length; g++) {
					if(this.nan(r[g]) || (r[g] == "e")) {
						cmp = pC;
					} else {
						cmp = pC.charCodeAt(0);
					}
					if(cmp == r[g]) {
						if(!this.nan(by[g])) {
							c = by[g];
						} else {
							c = by[g].charCodeAt(0);
						}
						if(this.is_ie) {
							return this.ie_replaceChar(w, pos, c);
						} else {
							return this.replaceChar(this.oc, i - pos, c);
						}
					}
				}
			}
		}
		return false;
	}
	
	this.main = function(w, k, i, a, noNormC) {
		var uk = this.up(k), bya = [this.db1, this.ab1, this.eb1, this.ob1, this.mocb1, this.trangb1], got = false, t = "d,D,a,A,a,A,o,O,u,U,e,E,o,O".split(",");
		var sfa = [this.ds1, this.as1, this.es1, this.os1, this.mocs1, this.trangs1], by = [], sf = [], method = AVIMGlobalConfig.method, h, g;
		if((method == 2) || ((method == 0) && (a[0] == "9"))) {
			this.DAWEO = "6789";
			this.SFJRX = "12534";
			this.S = "1";
			this.F = "2";
			this.J = "5";
			this.R = "3";
			this.X = "4";
			this.Z = "0";
			this.D = "9";
			this.FRX = "234";
			this.AEO = "6";
			this.moc = "7";
			this.trang = "8";
			this.them = "678";
			this.A = "^";
			this.E = "^";
			this.O = "^";
		} else if((method == 3) || ((method == 0) && (a[4] == "+"))) {
			this.DAWEO = "^+(D";
			this.SFJRX = "'`.?~";
			this.S = "'";
			this.F = "`";
			this.J = ".";
			this.R = "?";
			this.X = "~";
			this.Z = "-";
			this.D = "D";
			this.FRX = "`?~";
			this.AEO = "^";
			this.moc = "+";
			this.trang = "(";
			this.them = "^+(";
			this.A = "^";
			this.E = "^";
			this.O = "^";
		} else if((method == 4) || ((method == 0) && (a[4] == "*"))) {
			this.DAWEO = "^*(D";
			this.SFJRX = "'`.?~";
			this.S = "'";
			this.F = "`";
			this.J = ".";
			this.R = "?";
			this.X = "~";
			this.Z = "-";
			this.D = "D";
			this.FRX = "`?~";
			this.AEO = "^";
			this.moc = "*";
			this.trang = "(";
			this.them = "^*(";
			this.A = "^";
			this.E = "^";
			this.O = "^";
		} else if((method == 1) || ((method == 0) && (a[0] == "D"))) {
			this.SFJRX = "SFJRX";
			this.DAWEO = "DAWEO";
			this.D = 'D';
			this.S = 'S';
			this.F = 'F';
			this.J = 'J';
			this.R = 'R';
			this.X = 'X';
			this.Z = 'Z';
			this.FRX = "FRX";
			this.them = "AOEW";
			this.trang = "W";
			this.moc = "W";
			this.A = "A";
			this.E = "E";
			this.O = "O";
		}
		if(this.SFJRX.indexOf(uk) >= 0) {
			var ret = this.sr(w,k,i);
			got=true;
			if(ret) {
				return ret;
			}
		} else if(uk == this.Z) {
			sf = this.repSign(null);
			for(h = 0; h < this.english.length; h++) {
				sf[sf.length] = this.lowen.charCodeAt(h);
				sf[sf.length] = this.english.charCodeAt(h);
			}
			for(h = 0; h < 5; h++) {
				for(g = 0; g < this.skey.length; g++) {
					by[by.length] = this.skey[g];
				}
			}
			for(h = 0; h < t.length; h++) {
				by[by.length] = t[h];
			}
			got = true;
		} else {
			for(h = 0; h < a.length; h++) {
				if(a[h] == uk) {
					got = true;
					by = by.concat(bya[h]);
					sf = sf.concat(sfa[h]);
				}
			}
		}
		if(uk == this.moc) {
			this.whit = true;
		}
		if(!got) {
			if(noNormC) {
				return;
			} else {
				return this.normC(w, k, i);
			}
		}
		return this.DAWEOZ(k, w, by, sf, i, uk);
	}
	this.DAWEOZ = function(k, w, by, sf, i, uk) {
		if((this.DAWEO.indexOf(uk) >= 0) || (this.Z.indexOf(uk) >= 0)) {
			return this.tr(k, w, by, sf, i);
		}
	}
	this.normC = function(w, k, i) {
		var uk = this.up(k), u = this.repSign(null), fS, c, j, h, space = (k.charCodeAt(0) == 32) ? true : false;
		if(!this.is_ie && space) {
			return;
		}
		for(j = 1; j <= w.length; j++) {
			for(h = 0; h < u.length; h++) {
				if(u[h] == w.charCodeAt(w.length - j)) {
					if(h <= 23) {
						fS = this.S;
					} else if(h <= 47) {
						fS = this.F;
					} else if(h <= 71) {
						fS = this.J;
					} else if(h <= 95) {
						fS = this.R;
					} else {
						fS = this.X;
					}
					c = this.skey[h % 24];
					if((this.alphabet.indexOf(uk) < 0) && (this.D2.indexOf(uk) < 0)) {
						return w;
					}
					w = this.unV(w);
					if(!space && !this.changed) {
						w += k;
					}
					if(!this.is_ie) {
						var sp = this.oc.selectionStart, pos = sp;
						if(!this.changed) {
							var sst = this.oc.scrollTop;
							pos += k.length;
							if(!this.oc.data) {
								this.oc.value = this.oc.value.substr(0, sp) + k + this.oc.value.substr(this.oc.selectionEnd);
								this.changed = true;
								this.oc.scrollTop = sst;
							} else {
								this.oc.insertData(this.oc.pos, k);
								this.oc.pos++;
								this.range.setEnd(this.oc, this.oc.pos);
								this.specialChange = true;
							}
						}
						if(!this.oc.data) {
//							this.oc.setSelectionRange(pos, pos);
						}
						if(!this.ckspell(w, fS)) {
							this.replaceChar(this.oc, i - j, c);
							if(!this.oc.data) {
								var a = [this.D];
								this.main(w, fS, pos, a, false);
							} else {
								var ww = this.mozGetText(this.oc), a = [this.D];
								this.main(ww[0], fS, ww[1], a, false);
							}
						}
					} else {
						var ret = this.sr(w, fS, 0);
						if(space && ret) {
							ret += this.fcc(32);
						}
						if(ret) {
							return ret;
						}
					}
				}
			}
		}
	}
	
	this.DAWEOF = function(cc, k, g) {
		var ret = [g], kA = [this.A, this.moc, this.trang, this.E, this.O], z, a;
		var ccA = [this.aA, this.mocA, this.trangA, this.eA, this.oA], ccrA = [this.arA, this.mocrA, this.arA, this.erA, this.orA];
		for(a = 0; a < kA.length; a++) {
			if(k == kA[a]) {
				for(z = 0; z < ccA[a].length; z++) {
					if(cc == ccA[a][z]) {
						ret[1] = ccrA[a][z];
					}
				}
			}
		}
		if(ret[1]) {
			return ret;
		} else {
			return false;
		}
	}
	
	this.retKC = function(k) {
		if(k == this.S) {
			return [225,7845,7855,233,7871,237,243,7889,7899,250,7913,253,193,7844,7854,201,7870,205,211,7888,7898,218,7912,221];
		}
		if(k == this.F) {
			return [224,7847,7857,232,7873,236,242,7891,7901,249,7915,7923,192,7846,7856,200,7872,204,210,7890,7900,217,7914,7922];
		}
		if(k == this.J) {
			return [7841,7853,7863,7865,7879,7883,7885,7897,7907,7909,7921,7925,7840,7852,7862,7864,7878,7882,7884,7896,7906,7908,7920,7924];
		}
		if(k == this.R) {
			return [7843,7849,7859,7867,7875,7881,7887,7893,7903,7911,7917,7927,7842,7848,7858,7866,7874,7880,7886,7892,7902,7910,7916,7926];
		}
		if(k == this.X) {
			return [227,7851,7861,7869,7877,297,245,7895,7905,361,7919,7929,195,7850,7860,7868,7876,296,213,7894,7904,360,7918,7928];
		}
	}
	
	this.unV = function(w) {
		var u = this.repSign(null), b, a;
		for(a = 1; a <= w.length; a++) {
			for(b = 0; b < u.length; b++) {
				if(u[b] == w.charCodeAt(w.length - a)) {
					w = w.substr(0, w.length - a) + this.fcc(this.skey[b % 24]) + w.substr(w.length - a + 1);
				}
			}
		}
		return w;
	}
	
	this.unV2 = function(w) {
		var a, b;
		for(a = 1; a <= w.length; a++) {
			for(b = 0; b < this.skey.length; b++) {
				if(this.skey[b] == w.charCodeAt(w.length - a)) {
					w = w.substr(0, w.length - a) + this.skey2[b] + w.substr(w.length - a + 1);
				}
			}
		}
		return w;
	}
	
	this.repSign = function(k) {
		var t = [], u = [], a, b;
		for(a = 0; a < 5; a++) {
			if((k == null)||(this.SFJRX.substr(a, 1) != this.up(k))) {
				t = this.retKC(this.SFJRX.substr(a, 1));
				for(b = 0; b < t.length; b++) u[u.length] = t[b];
			}
		}
		return u;
	}
	
	this.sr = function(w, k, i) {
		var sf = this.getSF(), pos = this.findC(w, k, sf);
		if(pos) {
			if(pos[1]) {
				if(!this.is_ie) {
					this.replaceChar(this.oc, i-pos[0], pos[1]);
				} else {
					return this.ie_replaceChar(w, pos[0], pos[1]);
				}
			} else {
				var c = this.retUni(w, k, pos);
				if (!this.is_ie) {
					this.replaceChar(this.oc, i-pos, c);
				} else {
					return this.ie_replaceChar(w, pos, c);
				}
			}
		}
		return false;
	}
	
	this.retUni = function(w, k, pos) {
		var u = this.retKC(this.up(k)), uC, lC, c = w.charCodeAt(w.length - pos), a, t = this.fcc(c);
		for(a = 0; a < this.skey.length; a++) {
			if(this.skey[a] == c) {
				if(a < 12) {
					lC=a;
					uC=a+12;
				} else {
					lC = a - 12;
					uC=a;
				}
				if(t != this.up(t)) {
					return u[lC];
				}
				return u[uC];
			}
		}
	}
	
	this.ifInit = function(w) {
		var sel = w.getSelection();
		this.range = sel ? sel.getRangeAt(0) : document.createRange();
	}
	
	this.ifMoz = function(e) {
		var code = e.which, avim = this.AVIM, cwi = e.target.parentNode.wi;
		if(typeof(cwi) == "undefined") cwi = e.target.parentNode.parentNode.wi;
		if(e.ctrlKey || (e.altKey && (code != 92) && (code != 126))) return;
		avim.ifInit(cwi);
		var node = avim.range.endContainer, newPos;
		avim.sk = avim.fcc(code);
		avim.saveStr = "";
		if(avim.checkCode(code) || !avim.range.startOffset || (typeof(node.data) == 'undefined')) return;
		node.sel = false;
		if(node.data) {
			avim.saveStr = node.data.substr(avim.range.endOffset);
			if(avim.range.startOffset != avim.range.endOffset) {
				node.sel=true;
			}
			node.deleteData(avim.range.startOffset, node.data.length);
		}
		avim.range.setEnd(node, avim.range.endOffset);
		avim.range.setStart(node, 0);
		if(!node.data) {
			return;
		}
		node.value = node.data;
		node.pos = node.data.length;
		node.which=code;
		avim.start(node, e);
		node.insertData(node.data.length, avim.saveStr);
		newPos = node.data.length - avim.saveStr.length + avim.kl;
		avim.range.setEnd(node, newPos);
		avim.range.setStart(node, newPos);
		avim.kl = 0;
		if(avim.specialChange) {
			avim.specialChange = false;
			avim.changed = false;
			node.deleteData(node.pos - 1, 1);
		}
		if(avim.changed) {
			avim.changed = false;
			e.preventDefault();
		}
	}
	
	this.FKeyPress = function() {
		var obj = this.findF();
		this.sk = this.fcc(obj.event.keyCode);
		if(this.checkCode(obj.event.keyCode) || (obj.event.ctrlKey && (obj.event.keyCode != 92) && (obj.event.keyCode != 126))) {
			return;
		}
		this.start(obj, this.sk);
	}
	
	this.checkCode = function(code) {
		if(((AVIMGlobalConfig.onOff == 0) || ((code < 45) && (code != 42) && (code != 32) && (code != 39) && (code != 40) && (code != 43)) || (code == 145) || (code == 255))) {
			return true;
		}
	}
	
	this.notWord = function(w) {
		var str = "\ \r\n#,\\;.:-_()<>+-*/=?!\"$%{}[]\'~|^\@\&\t" + this.fcc(160);
		return (str.indexOf(w) >= 0);
	}
	
	this.nan = function(w) {
		if (isNaN(w) || (w == 'e')) {
			return true;
		} else {
			return false;
		}
	}
	
	this.up = function(w) {
		w = w.toUpperCase();
		if(this.isKHTML) {
			var str = "êôơâăưếốớấắứềồờầằừễỗỡẫẵữệộợậặự", rep="ÊÔƠÂĂƯẾỐỚẤẮỨỀỒỜẦẰỪỄỖỠẪẴỮỆỘỢẶỰ", z, io;
			for(z = 0; z < w.length; z++) {
				io = str.indexOf(w.substr(z, 1));
				if(io >= 0) {
					w = w.substr(0, z) + rep.substr(io, 1) + w.substr(z + 1);
				}
			}
		}
		return w;
	}
	
	this.findIgnore = function(el) {
		var va = AVIMGlobalConfig.exclude, i;
		for(i = 0; i < va.length; i++) {
			if((el.id == va[i]) && (va[i].length > 0)) {
				return true;
			}
		}
	}
	
	this.findF = function() {
		var g;
		for(g = 0; g < this.fID.length; g++) {
			if(this.findIgnore(this.fID[g])) return;
			this.frame = this.fID[g];
			if(typeof(this.frame) != "undefined") {
				try {
					if (this.frame.contentWindow.document && this.frame.contentWindow.event) {
						return this.frame.contentWindow;
					}
				} catch(e) {
					if (this.frame.document && this.frame.event) {
						return this.frame;
					}
				}
			}
		}
	}
	
	this.keyPressHandler = function(e) {
		if(!this.support) {
			return;
		}
		if(!this.is_ie) {
			var el = e.target, code = e.which;
			if(e.ctrlKey) {
				return;
			}
			if(e.altKey && (code != 92) && (code != 126)) {
				return;
			}
		} else {
			var el = window.event.srcElement, code = window.event.keyCode;
			if(window.event.ctrlKey && (code != 92) && (code != 126)) {
				return;
			}
		}
		if(((el.type != 'textarea') && (el.type != 'text')) || this.checkCode(code)) {
			return;
		}
		this.sk = this.fcc(code);
		if(this.findIgnore(el)) {
			return;
		}
		if(!this.is_ie) {
			this.start(el, e);
		} else {
			this.start(el, this.sk);
		}
		if(this.changed) {
			this.changed = false;
			return false;
		}
		return true;
	}
	
	this.attachEvt = function(obj, evt, handle, capture) {
		if(this.is_ie) {
			obj.attachEvent("on" + evt, handle);
		} else {
			obj.addEventListener(evt, handle, capture);
		}
	}
	
	this.keyDownHandler = function(e) {
		if(e == "iframe") {
			this.frame = this.findF();
			var key = this.frame.event.keyCode;
		} else {
			var key = (!this.is_ie) ? e.which : window.event.keyCode;
		}
		if (key == 123) {
			document.getElementById('AVIMControl').style.display = (document.getElementById('AVIMControl').style.display == 'none') ? 'block' : 'none';
		}
	}
}

function AVIMInit(AVIM) {
	var kkk = false;
	if(AVIM.support && !AVIM.isKHTML) {
		if(AVIM.is_opera) {
			if(AVIM.operaVersion < 9) {
				return;
			}
		}
		for(AVIM.g = 0; AVIM.g < AVIM.fID.length; AVIM.g++) {
			if(AVIM.findIgnore(AVIM.fID[AVIM.g])) {
				continue;
			}
			if(AVIM.is_ie) {
				var doc;
				try {
					AVIM.frame = AVIM.fID[AVIM.g];
					if(typeof(AVIM.frame) != "undefined") {
						if(AVIM.frame.contentWindow.document) {
							doc = AVIM.frame.contentWindow.document;
						} else if(AVIM.frame.document) {
							doc = AVIM.frame.document;
						}
					}
				} catch(e) {}
				if(doc && ((AVIM.up(doc.designMode) == "ON") || doc.body.contentEditable)) {
					for (var l = 0; l < AVIM.attached.length; l++) {
						if (doc == AVIM.attached[l]) {
							kkk = true;
							break;
						}
					}
					if (!kkk) {
						AVIM.attached[AVIM.attached.length] = doc;
						AVIM.attachEvt(doc, "keydown", function() {
							AVIM.keyDownHandler("iframe");
						}, false);
						AVIM.attachEvt(doc, "keypress", function() {
							AVIM.FKeyPress();
							if(AVIM.changed) {
								AVIM.changed = false;
								return false;
							}
						}, false);
					}
				}
			} else {
				var iframedit;
				try {
					AVIM.wi = AVIM.fID[AVIM.g].contentWindow;
					iframedit = AVIM.wi.document;
					iframedit.wi = AVIM.wi;
					if(iframedit && (AVIM.up(iframedit.designMode) == "ON")) {
						iframedit.AVIM = AVIM;
						AVIM.attachEvt(iframedit, "keypress", AVIM.ifMoz, false);
						AVIM.attachEvt(iframedit, "keydown", AVIM.keyDownHandler, false);
					}
				} catch(e) {}
			}
		}
	}
}
function Popup(){
	this.popup_count = 0;
	
    this.add = function(id, title, content){
    	$('body').append('<div class="popup" id="'+id+'">\
    	        <div class="popup-outer">\
                <div class="popup-title">'+title+'<a onclick="generateEvent(\'PopupRemove\', {id: \''+id+'\'})" class="close-popup">x</a></div>\
                <div class="popup-content">'+content+'</div>\
            </div>\
    	</div>');
        this.popup_count++;
        $('#shadow').fadeIn();
        $('#'+id).fadeIn();
        $('#'+id).css('margin-left',-($('#'+id+' .popup-content').width()/2+18));
        $('#'+id).css('margin-top',-($('#'+id+' .popup-content').height()/2+50));
    }
    
    this.remove = function(id){
    	this.popup_count--;
    	$('#'+id).fadeOut();
    	$('#'+id).remove();
    	if($('.popup:visible').length == 0){
    		$('#shadow').fadeOut();
    	}
    }
	 
    this.error = function(msg){
    	this.add('popup-error', 'Có lỗi', '<div class="popup-error">'+msg+'</div>\
			<div class="popup-toolbar-msg"><a class="button" onclick="generateEvent(\'PopupRemove\', {id: \'popup-error\'})">Đồng ý</a></div>\
    	');
    }
    
    this.msg = function(msg){
    	this.add('popup-msg', 'Thông báo', '<div class="popup-msg">'+msg+'</div>\
			<div class="popup-toolbar-msg"><a class="button" onclick="generateEvent(\'PopupRemove\', {id: \'popup-msg\'})">Đồng ý</a></div>\
    	');
    }
}
(function ($) {
    $.format = (function () {

		function strMonth(value) {
			switch (parseInt(value)) {
                case 1:
                    return "Jan";
                case 2:
                    return "Feb";
                case 3:
                    return "Mar";
                case 4:
                    return "Apr";
                case 5:
                    return "May";
                case 6:
                    return "Jun";
                case 7:
                    return "Jul";
                case 8:
                    return "Aug";
                case 9:
                    return "Sep";
                case 10:
                    return "Oct";
                case 11:
                    return "Nov";
                case 12:
                    return "Dec";
                default:
                    return value;
			}
		}
	
        var parseMonth = function (value) {
            switch (value) {
                case "Jan":
                    return "01";
                case "Feb":
                    return "02";
                case "Mar":
                    return "03";
                case "Apr":
                    return "04";
                case "May":
                    return "05";
                case "Jun":
                    return "06";
                case "Jul":
                    return "07";
                case "Aug":
                    return "08";
                case "Sep":
                    return "09";
                case "Oct":
                    return "10";
                case "Nov":
                    return "11";
                case "Dec":
                    return "12";
                default:
                    return value;
            }
        };

        var parseTime = function (value) {
            var retValue = value;
            if (retValue.indexOf(".") !== -1) {
                retValue = retValue.substring(0, retValue.indexOf("."));
            }

            var values3 = retValue.split(":");

            if (values3.length === 3) {
                hour = values3[0];
                minute = values3[1];
                second = values3[2];

                return {
                    time: retValue,
                    hour: hour,
                    minute: minute,
                    second: second
                };
            } else {
                return {
                    time: "",
                    hour: "",
                    minute: "",
                    second: ""
                };
            }
        };

        return {
            date: function (value, format) {
                //value = new java.util.Date()
                //2009-12-18 10:54:50.546
                try {
                    var year = null;
                    var month = null;
                    var dayOfMonth = null;
                    var time = null; //json, time, hour, minute, second
                    if (typeof value.getFullYear === "function") {
                        year = value.getFullYear();
                        month = value.getMonth() + 1;
                        dayOfMonth = value.getDate();
                        time = parseTime(value.toTimeString());
                    } else if (value.search(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.?\d{0,3}\+\d{2}:\d{2}/) != -1) { // 2009-04-19T16:11:05+02:00
                        var values = value.split(/[T\+-]/);
                        year = values[0];
                        month = values[1];
                        dayOfMonth = values[2];
                        time = parseTime(values[3].split(".")[0]);
                    } else {
                        var values = value.split(" ");
                        switch (values.length) {
                            case 6: //Wed Jan 13 10:43:41 CET 2010
                                year = values[5];
                                month = parseMonth(values[1]);
                                dayOfMonth = values[2];
                                time = parseTime(values[3]);
                                break;
                            case 2: //2009-12-18 10:54:50.546
                                var values2 = values[0].split("-");
                                year = values2[0];
                                month = values2[1];
                                dayOfMonth = values2[2];
                                time = parseTime(values[1]);
                                break;
						    case 7: // Tue Mar 01 2011 12:01:42 GMT-0800 (PST)
	                            year = values[3];
	                            month = parseMonth(values[1]);
	                            dayOfMonth = values[2];
	                            time = parseTime(values[4]);
	                            break;
                            default:
                                return value;
                        }
                    }

                    var pattern = "";
                    var retValue = "";
                    //Issue 1 - variable scope issue in format.date 
                    //Thanks jakemonO
                    for (var i = 0; i < format.length; i++) {
                        var currentPattern = format.charAt(i);
                        pattern += currentPattern;
                        switch (pattern) {
                            case "dd":
                                retValue += dayOfMonth;
                                pattern = "";
                                break;
                            case "MMM":
                                retValue += strMonth(month);
                                pattern = "";
                                break;
                            case "MM":
                                if (format.charAt(i+1) == "M") {
                                    break;
                                }
                                retValue += month;
                                pattern = "";
                                break;
                            case "yyyy":
                                retValue += year;
                                pattern = "";
                                break;
                            case "HH":
                                retValue += time.hour;
                                pattern = "";
                                break;
                            case "hh":
                                //time.hour is "00" as string == is used instead of ===
                                retValue += (time.hour == 0 ? 12 : time.hour < 13 ? time.hour : time.hour - 12);
                                pattern = "";
                                break;
                            case "mm":
                                retValue += time.minute;
                                pattern = "";
                                break;
                            case "ss":
                                //ensure only seconds are added to the return string
                                retValue += time.second.substring(0, 2);
                                pattern = "";
                                break;
                            //case "tz":
                            //    //parse out the timezone information
                            //    retValue += time.second.substring(3, time.second.length);
                            //    pattern = "";
                            //    break;
                            case "a":
                                retValue += time.hour >= 12 ? "PM" : "AM";
                                pattern = "";
                                break;
                            case " ":
                                retValue += currentPattern;
                                pattern = "";
                                break;
                            case "/":
                                retValue += currentPattern;
                                pattern = "";
                                break;
                            case ":":
                                retValue += currentPattern;
                                pattern = "";
                                break;
                            default:
                                if (pattern.length === 2 && pattern.indexOf("y") !== 0) {
                                    retValue += pattern.substring(0, 1);
                                    pattern = pattern.substring(1, 2);
                                } else if ((pattern.length === 3 && pattern.indexOf("yyy") === -1)) {
                                    pattern = "";
                                }
                        }
                    }
                    return retValue;
                } catch (e) {
                	log(e);
                    return value;
                }
            }
        };
    } ());
} (jQuery));


$(document).ready(function () {
    $(".shortDateFormat").each(function (idx, elem) {
        if ($(elem).is(":input")) {
            $(elem).val($.format.date($(elem).val(), 'dd/MM/yyyy'));
        } else {
            $(elem).text($.format.date($(elem).text(), 'dd/MM/yyyy'));
        }
    });
    $(".longDateFormat").each(function (idx, elem) {
        if ($(elem).is(":input")) {
            $(elem).val($.format.date($(elem).val(), 'dd/MM/yyyy hh:mm:ss'));
        } else {
            $(elem).text($.format.date($(elem).text(), 'dd/MM/yyyy hh:mm:ss'));
        }
    });
});

/*
 * jQuery EasIng v1.1.2 - http://gsgd.co.uk/sandbox/jquery.easIng.php
 *
 * Uses the built In easIng capabilities added In jQuery 1.1
 * to offer multiple easIng options
 *
 * Copyright (c) 2007 George Smith
 * Licensed under the MIT License:
 *   http://www.opensource.org/licenses/mit-license.php
 */

// t: current time, b: begInnIng value, c: change In value, d: duration

jQuery.extend( jQuery.easing,
{
	easeInQuad: function (x, t, b, c, d) {
		return c*(t/=d)*t + b;
	},
	easeOutQuad: function (x, t, b, c, d) {
		return -c *(t/=d)*(t-2) + b;
	},
	easeInOutQuad: function (x, t, b, c, d) {
		if ((t/=d/2) < 1) return c/2*t*t + b;
		return -c/2 * ((--t)*(t-2) - 1) + b;
	},
	easeInCubic: function (x, t, b, c, d) {
		return c*(t/=d)*t*t + b;
	},
	easeOutCubic: function (x, t, b, c, d) {
		return c*((t=t/d-1)*t*t + 1) + b;
	},
	easeInOutCubic: function (x, t, b, c, d) {
		if ((t/=d/2) < 1) return c/2*t*t*t + b;
		return c/2*((t-=2)*t*t + 2) + b;
	},
	easeInQuart: function (x, t, b, c, d) {
		return c*(t/=d)*t*t*t + b;
	},
	easeOutQuart: function (x, t, b, c, d) {
		return -c * ((t=t/d-1)*t*t*t - 1) + b;
	},
	easeInOutQuart: function (x, t, b, c, d) {
		if ((t/=d/2) < 1) return c/2*t*t*t*t + b;
		return -c/2 * ((t-=2)*t*t*t - 2) + b;
	},
	easeInQuint: function (x, t, b, c, d) {
		return c*(t/=d)*t*t*t*t + b;
	},
	easeOutQuint: function (x, t, b, c, d) {
		return c*((t=t/d-1)*t*t*t*t + 1) + b;
	},
	easeInOutQuint: function (x, t, b, c, d) {
		if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;
		return c/2*((t-=2)*t*t*t*t + 2) + b;
	},
	easeInSine: function (x, t, b, c, d) {
		return -c * Math.cos(t/d * (Math.PI/2)) + c + b;
	},
	easeOutSine: function (x, t, b, c, d) {
		return c * Math.sin(t/d * (Math.PI/2)) + b;
	},
	easeInOutSine: function (x, t, b, c, d) {
		return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
	},
	easeInExpo: function (x, t, b, c, d) {
		return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
	},
	easeOutExpo: function (x, t, b, c, d) {
		return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
	},
	easeInOutExpo: function (x, t, b, c, d) {
		if (t==0) return b;
		if (t==d) return b+c;
		if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
		return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
	},
	easeInCirc: function (x, t, b, c, d) {
		return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;
	},
	easeOutCirc: function (x, t, b, c, d) {
		return c * Math.sqrt(1 - (t=t/d-1)*t) + b;
	},
	easeInOutCirc: function (x, t, b, c, d) {
		if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;
		return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;
	},
	easeInElastic: function (x, t, b, c, d) {
		var s=1.70158;var p=0;var a=c;
		if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
		if (a < Math.abs(c)) { a=c; var s=p/4; }
		else var s = p/(2*Math.PI) * Math.asin (c/a);
		return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
	},
	easeOutElastic: function (x, t, b, c, d) {
		var s=1.70158;var p=0;var a=c;
		if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
		if (a < Math.abs(c)) { a=c; var s=p/4; }
		else var s = p/(2*Math.PI) * Math.asin (c/a);
		return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
	},
	easeInOutElastic: function (x, t, b, c, d) {
		var s=1.70158;var p=0;var a=c;
		if (t==0) return b;  if ((t/=d/2)==2) return b+c;  if (!p) p=d*(.3*1.5);
		if (a < Math.abs(c)) { a=c; var s=p/4; }
		else var s = p/(2*Math.PI) * Math.asin (c/a);
		if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
		return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;
	},
	easeInBack: function (x, t, b, c, d, s) {
		if (s == undefined) s = 1.70158;
		return c*(t/=d)*t*((s+1)*t - s) + b;
	},
	easeOutBack: function (x, t, b, c, d, s) {
		if (s == undefined) s = 1.70158;
		return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
	},
	easeInOutBack: function (x, t, b, c, d, s) {
		if (s == undefined) s = 1.70158; 
		if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
		return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
	},
	easeInBounce: function (x, t, b, c, d) {
		return c - jQuery.easing.easeOutBounce (x, d-t, 0, c, d) + b;
	},
	easeOutBounce: function (x, t, b, c, d) {
		if ((t/=d) < (1/2.75)) {
			return c*(7.5625*t*t) + b;
		} else if (t < (2/2.75)) {
			return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
		} else if (t < (2.5/2.75)) {
			return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
		} else {
			return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
		}
	},
	easeInOutBounce: function (x, t, b, c, d) {
		if (t < d/2) return jQuery.easing.easeInBounce (x, t*2, 0, c, d) * .5 + b;
		return jQuery.easing.easeOutBounce (x, t*2-d, 0, c, d) * .5 + c*.5 + b;
	}
});
(function(d) {
	var e = 0;
	d
			.widget(
					"ui.autocomplete",
					{
						options : {
							appendTo : "body",
							delay : 300,
							minLength : 1,
							position : {
								my : "left top",
								at : "left bottom",
								collision : "none"
							},
							source : null
						},
						pending : 0,
						_create : function() {
							var a = this, b = this.element[0].ownerDocument, g;
							this.element
									.addClass("ui-autocomplete-input")
									.attr("autocomplete", "off")
									.attr({
										role : "textbox",
										"aria-autocomplete" : "list",
										"aria-haspopup" : "true"
									})
									.bind(
											"keydown.autocomplete",
											function(c) {
												if (!(a.options.disabled || a.element
														.attr("readonly"))) {
													g = false;
													var f = d.ui.keyCode;
													switch (c.keyCode) {
													case f.PAGE_UP:
														a._move("previousPage",
																c);
														break;
													case f.PAGE_DOWN:
														a._move("nextPage", c);
														break;
													case f.UP:
														a._move("previous", c);
														c.preventDefault();
														break;
													case f.DOWN:
														a._move("next", c);
														c.preventDefault();
														break;
													case f.ENTER:
													case f.NUMPAD_ENTER:
														var id = a.element.attr("id");
														// chỉ lấy thông tin của ô input search
														if(id == "to" || id == "toPerson"){
															if (a.menu.active) {
																g = true;
																c.preventDefault();
															} else{
																if ($('#tabs li.ui-tabs-selected span.ui-tab-font').hasClass('tab-person')){
																	onClickPerson();
																} else{
																	if ($('#tabs li.ui-tabs-selected span.ui-tab-font').hasClass('tab-knowledge')){
																		onClickQuestion();
																	}
																}
															}
														}
													case f.TAB:
														if (!a.menu.active)
															return;
														a.menu.select(c);
														break;
													case f.ESCAPE:
														a.element.val(a.term);
														a.close(c);
														break;
													case f.BACKSPACE:
														var tmp_a = a.menu.element;
														//console.log("BACK SPACE");
														if (a.element.val() == 0){
															$('input[class="ui-autocomplete-input"]').prev("span").remove();
															$('li[role="menuitem"]').each(function(){$(this).remove();});
														}
														var w = 0;
														$("#friends span").each(function(){
															w += $(this).outerWidth(true);
														});
														var adaptive_width = $("#friends").width() - w;
														var min = 120;
														if (adaptive_width < min){
															adaptive_width = $("#friends").width();
														}
														$("#to").width(adaptive_width);
													default:
														clearTimeout(a.searching);
														a.searching = setTimeout(
																function() {
																	if (a.term != a.element
																			.val()) {
																		a.selectedItem = null;
																		a
																				.search(
																						null,
																						c)
																	}
																},
																a.options.delay);
														break
													}
												}
											}).bind("keypress.autocomplete",
											function(c) {
												if (g) {
													g = false;
													c.preventDefault()
												}
											}).bind(
											"focus.autocomplete",
											function() {
												if (!a.options.disabled) {
													a.selectedItem = null;
													a.previous = a.element
															.val()
												}
											}).bind(
											"blur.autocomplete",
											function(c) {
												if (!a.options.disabled) {
													clearTimeout(a.searching);
													a.closing = setTimeout(
															function() {
																a.close(c);
																a._change(c)
															}, 150)
												}
											});
//							//console.log("Init source here");
							this._initSource();
							this.response = function() {
								return a._response.apply(a, arguments)
							};
							this.menu = d("<ul></ul>")
									.addClass("ui-autocomplete")
									.appendTo(
											d(this.options.appendTo || "body",
													b)[0])
									.mousedown(
											function(c) {
												var f = a.menu.element[0];
												d(c.target).closest(
														".ui-menu-item").length
														|| setTimeout(
																function() {
																	d(document)
																			.one(
																					"mousedown",
																					function(
																							h) {
																						h.target !== a.element[0]
																								&& h.target !== f
																								&& !d.ui
																										.contains(
																												f,
																												h.target)
																								&& a
																										.close()
																					})
																}, 1);
												setTimeout(function() {
													clearTimeout(a.closing)
												}, 13)
											})
									.menu(
											{
												focus : function(c, f) {
													f = f.item
															.data("item.autocomplete");
													false !== a._trigger(
															"focus", c, {
																item : f
															})
															&& /^key/
																	.test(c.originalEvent.type)
															&& a.element
																	.val(f.value)
												},
												selected : function(c, f) {
													var h = f.item
															.data("item.autocomplete"), i = a.previous;
													if (a.element[0] !== b.activeElement) {
														a.element.focus();
														a.previous = i;
														setTimeout(function() {
															a.previous = i;
															a.selectedItem = h
														}, 1)
													}
													false !== a._trigger(
															"select", c, {
																item : h
															})
															&& a.element
																	.val("");
													a.term = a.element.val();
													a.close(c);
													a.selectedItem = h
												},
												blur : function() {
													a.menu.element
															.is(":visible")
															&& a.element.val() !== a.term
															&& a.element
																	.val(a.term)
												}
											})
									.zIndex(this.element.zIndex() + 1).css({
										top : 0,
										left : 0
									}).hide().data("menu");
							d.fn.bgiframe && this.menu.element.bgiframe()
						},
						destroy : function() {
							this.element.removeClass("ui-autocomplete-input")
									.removeAttr("autocomplete").removeAttr(
											"role").removeAttr(
											"aria-autocomplete").removeAttr(
											"aria-haspopup");
							this.menu.element.remove();
							d.Widget.prototype.destroy.call(this)
						},
						_setOption : function(a, b) {
							d.Widget.prototype._setOption
									.apply(this, arguments);
							a === "source" && this._initSource();
							if (a === "appendTo")
								this.menu.element.appendTo(d(b || "body",
										this.element[0].ownerDocument)[0]);
							a === "disabled" && b && this.xhr
									&& this.xhr.abort()
						},
						_initSource : function() {
							var a = this, b, g;
//							console.log("_initSource");
//							console.log(this.options.source + "");
							if (d.isArray(this.options.source)) {
								b = this.options.source;
								this.source = function(c, f) {
//									console.log("dong anh");
//									console.log(f);
									f(d.ui.autocomplete.filter(b, c.term))
								}
							} else if (typeof this.options.source === "string") {
								g = this.options.source;
								this.source = function(c, f) {
									a.xhr && a.xhr.abort();
									a.xhr = d.ajax({
										url : g,
										data : c,
										dataType : "json",
										autocompleteRequest : ++e,
										success : function(h) {
											this.autocompleteRequest === e
													&& f(h)
										},
										error : function() {
											this.autocompleteRequest === e
													&& f([])
										}
									})
								}
							} else
								this.source = this.options.source
						},
						search : function(a, b) {
							a = a != null ? a : this.element.val();
							this.term = this.element.val();
							if (a.length < this.options.minLength)
								return this.close(b);
							clearTimeout(this.closing);
							if (this._trigger("search", b) !== false)
								return this._search(a)
						},
						_search : function(a) {
							this.pending++;
							this.element.addClass("ui-autocomplete-loading");
							this.source({
								term : a
							}, this.response)
						},
						_response : function(a) {
							if (!this.options.disabled && a && a.length) {
								a = this._normalize(a);
								this._suggest(a);
								this._trigger("open");
							} else
								this.close();
							this.pending--;
							this.pending
									|| this.element
											.removeClass("ui-autocomplete-loading")
						},
						close : function(a) {
							clearTimeout(this.closing);
							if (this.menu.element.is(":visible")) {
								this.menu.element.hide();
								this.menu.deactivate();
								this._trigger("close", a)
							}
						},
						_change : function(a) {
							this.previous !== this.element.val()
									&& this._trigger("change", a, {
										item : this.selectedItem
									})
						},
						_normalize : function(a) {
							if (a.length && a[0].label && a[0].value)
								return a;
							return d.map(a, function(b) {
								if (typeof b === "string")
									return {
										label : b,
										value : b
									};
								return d.extend({
									label : b.label || b.value,
									value : b.value || b.label
//									id: b.id || "Long"
								}, b)
							})
						},
						_suggest : function(a) {
							var b = this.menu.element.empty().zIndex(
									this.element.zIndex() + 1);
							this._renderMenu(b, a);
							this.menu.deactivate();
							this.menu.refresh();
							b.show();
							this._resizeMenu();
							b.position(d.extend({
								of : this.element
							}, this.options.position))
						},
						_resizeMenu : function() {
							var a = this.menu.element;
							a.outerWidth(Math.max(a.width("").outerWidth(),
									this.element.outerWidth()))
						},
						_renderMenu : function(a, b) {
							var g = this;
							d.each(b, function(c, f) {
								g._renderItem(a, f)
							})
						},
						_renderItem : function(a, b) {
							var label = b.label;
							var str = "<a></a>";
							var objParam = {};
							if (typeof b != 'object')	{
								objParam = b;
							} else {
								objParam.label = b.label;
								objParam.value = b.label;
								objParam.id = b.value;
								objParam.type = b.type;
							}
							
							var btn = "";
							var maxCatchwords = 4;
							if (objParam.type == 'expertise')	{
								str = "<a catch_id = '"+objParam.id+"' catch = '"+escape(objParam.label)+"'class=ui-auto-item-expertise>"+objParam.label+"</a>";
								btn = "<span class=ui-auto-item-expertise-label>Chuyên môn</span><span class=ui-auto-item-expertise-label style='float:right'>"+escape(b.follow)+" người quan tâm</span>";
							} else if (objParam.type == 'question')	{
								var cbtn = "";
								var catchwords = b.catchwords;
								if (catchwords != undefined)	{
									for (var i=0; i<catchwords.length && i<maxCatchwords; i++){
										cbtn += "<span class=ui-button-text>" + catchwords[i] + "</span>";
									}
								}
								str = "<a question_id = '"+objParam.id+"' question = '"+escape(objParam.label)+"'><span class='question_label'>"+objParam.label+cbtn+"</span></a>";
							} else if (objParam.type == 'ask') {
								str = "<a class='ask'>"+objParam.label+" <span class='action_button'>Đặt câu hỏi"+"</span></a>";
							} else if (objParam.type == 'email') {
								str = "<a class='email _left'>"+objParam.label+"</a>";
							}
							 else if (objParam.type == 'person')	{
								var avatar = b.avatar;
								str = "<a class='person'><img onerror='this.src=\"resource/images/unknown.png\"' src='resource/avatar/"+avatar+"'></img><span style='float: right; color: #202020'>"+b.ans+" câu trả lời</span>";
								var catchwords = b.catchwords;
								btn = "<span class='person-name'>"+objParam.label+"</span><br />";
								if(catchwords != undefined && catchwords.length > 0)
								{
									for (var i=0; i<catchwords.length && i<maxCatchwords; i++){
										btn += "<span class=ui-button-text>" + catchwords[i] + "</span>";
									}
								}
								btn += "</span></a>";
								if (catchwords != undefined && catchwords.length == 0)
									btn += "<br />";
							}
							
							return d("<li></li>").data("item.autocomplete", objParam)
									.append(d(str).append(d(btn)))
									.appendTo(a);
						},
						_move : function(a, b) {
							if (this.menu.element.is(":visible"))
								if (this.menu.first() && /^previous/.test(a)
										|| this.menu.last() && /^next/.test(a)) {
									this.element.val(this.term);
									this.menu.deactivate()
								} else
									this.menu[a](b);
							else
								this.search(null, b)
						},
						widget : function() {
							return this.menu.element
						}
					});
	d.extend(d.ui.autocomplete, {
		escapeRegex : function(a) {
			return a.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&")
		},
		filter : function(a, b) {
			var g = new RegExp(d.ui.autocomplete.escapeRegex(b), "i");
			return d.grep(a, function(c) {
				return g.test(c.label || c.value || c)
			})
		}
	})
})(jQuery);
(function(d) {
	d
			.widget(
					"ui.menu",
					{
						_create : function() {
							var e = this;
							this.element
									.addClass(
											"ui-menu ui-widget ui-widget-content ui-corner-all")
									.attr(
											{
												role : "listbox",
												"aria-activedescendant" : "ui-active-menuitem"
											})
									.click(
											function(a) {
												if (d(a.target).closest(
														".ui-menu-item a").length) {
													a.preventDefault();
													e.select(a)
												}
											});
							this.refresh()
						},
						refresh : function() {
							var e = this;
							this.element.children(
									"li:not(.ui-menu-item):has(a)").addClass(
									"ui-menu-item").attr("role", "menuitem")
									.children("a").addClass("ui-corner-all")
									.attr("tabindex", -1).mouseenter(
											function(a) {
												e.activate(a, d(this).parent())
											}).mouseleave(function() {
										e.deactivate()
									})
						},
						activate : function(e, a) {
							this.deactivate();
							if (this.hasScroll()) {
								var b = a.offset().top
										- this.element.offset().top, g = this.element
										.attr("scrollTop"), c = this.element
										.height();
								if (b < 0)
									this.element.attr("scrollTop", g + b);
								else
									b >= c
											&& this.element.attr("scrollTop", g
													+ b - c + a.height())
							}
							this.active = a.eq(0).children("a").addClass(
									"ui-state-hover").attr("id",
									"ui-active-menuitem").end();
							this._trigger("focus", e, {
								item : a
							})
						},
						deactivate : function() {
							if (this.active) {
								this.active.children("a").removeClass(
										"ui-state-hover").removeAttr("id");
								this._trigger("blur");
								this.active = null
							}
						},
						next : function(e) {
							this.move("next", ".ui-menu-item:first", e)
						},
						previous : function(e) {
							this.move("prev", ".ui-menu-item:last", e)
						},
						first : function() {
							return this.active
									&& !this.active.prevAll(".ui-menu-item").length
						},
						last : function() {
							return this.active
									&& !this.active.nextAll(".ui-menu-item").length
						},
						move : function(e, a, b) {
							if (this.active) {
								e = this.active[e + "All"](".ui-menu-item").eq(
										0);
								e.length ? this.activate(b, e) : this.activate(
										b, this.element.children(a))
							} else
								this.activate(b, this.element.children(a))
						},
						nextPage : function(e) {
							if (this.hasScroll())
								if (!this.active || this.last())
									this.activate(e, this.element
											.children(".ui-menu-item:first"));
								else {
									var a = this.active.offset().top, b = this.element
											.height(), g = this.element
											.children(".ui-menu-item")
											.filter(
													function() {
														var c = d(this)
																.offset().top
																- a
																- b
																+ d(this)
																		.height();
														return c < 10
																&& c > -10
													});
									g.length
											|| (g = this.element
													.children(".ui-menu-item:last"));
									this.activate(e, g)
								}
							else
								this.activate(e, this.element.children(
										".ui-menu-item").filter(
										!this.active || this.last() ? ":first"
												: ":last"))
						},
						previousPage : function(e) {
							if (this.hasScroll())
								if (!this.active || this.first())
									this.activate(e, this.element
											.children(".ui-menu-item:last"));
								else {
									var a = this.active.offset().top, b = this.element
											.height();
									result = this.element.children(
											".ui-menu-item").filter(
											function() {
												var g = d(this).offset().top
														- a + b
														- d(this).height();
												return g < 10 && g > -10
											});
									result.length
											|| (result = this.element
													.children(".ui-menu-item:first"));
									this.activate(e, result)
								}
							else
								this.activate(e, this.element.children(
										".ui-menu-item").filter(
										!this.active || this.first() ? ":last"
												: ":first"))
						},
						hasScroll : function() {
							return this.element.height() < this.element
									.attr("scrollHeight")
						},
						select : function(e) {
							this._trigger("selected", e, {
								item : this.active
							})
						}
					})
})(jQuery);;

/**
 * TextAreaExpander plugin for jQuery
 * v1.0
 * Expands or contracts a textarea height depending on the
 * quatity of content entered by the user in the box.
 *
 * By Craig Buckler, Optimalworks.net
 *
 * As featured on SitePoint.com:
 * http://www.sitepoint.com/blogs/2009/07/29/build-auto-expanding-textarea-1/
 *
 * Please use as you wish at your own risk.
 */

/**
 * Usage:
 *
 * From JavaScript, use:
 *     $(<node>).TextAreaExpander(<minHeight>, <maxHeight>);
 *     where:
 *       <node> is the DOM node selector, e.g. "textarea"
 *       <minHeight> is the minimum textarea height in pixels (optional)
 *       <maxHeight> is the maximum textarea height in pixels (optional)
 *
 * Alternatively, in you HTML:
 *     Assign a class of "expand" to any <textarea> tag.
 *     e.g. <textarea name="textarea1" rows="3" cols="40" class="expand"></textarea>
 *
 *     Or assign a class of "expandMIN-MAX" to set the <textarea> minimum and maximum height.
 *     e.g. <textarea name="textarea1" rows="3" cols="40" class="expand50-200"></textarea>
 *     The textarea will use an appropriate height between 50 and 200 pixels.
 */

(function($) {

	// jQuery plugin definition
	$.fn.TextAreaExpander = function(minHeight, maxHeight) {

		var hCheck = !($.browser.msie || $.browser.opera);

		// resize a textarea
		function ResizeTextarea(e) {

			// event or initialize element?
			e = e.target || e;

			// find content length and box width
			var vlen = e.value.length, ewidth = e.offsetWidth;
			if (vlen != e.valLength || ewidth != e.boxWidth) {
				if (hCheck && (vlen < e.valLength || ewidth != e.boxWidth))	{
					e.style.height = "0px";
				}
				//console.log(e.expandMin);
				var h = Math.max(e.expandMin, Math.min(e.scrollHeight, e.expandMax));

				e.style.overflow = (e.scrollHeight > h ? "auto" : "hidden");
				e.style.height = h + "px";

				e.valLength = vlen;
				e.boxWidth = ewidth;
			}

			return true;
		};

		// initialize
		this.each(function() {

			// is a textarea?
			if (this.nodeName.toLowerCase() != "textarea") return;

			// set height restrictions
			var p = this.className.match(/expandable(\d+)\-*(\d+)*/i);
			this.expandMin = minHeight || (p ? parseInt('0'+p[1], 10) : 0);
			this.expandMax = maxHeight || (p ? parseInt('0'+p[2], 10) : 99999);

			// initial resize
			ResizeTextarea(this);

			// zero vertical padding and add events
			if (!this.Initialized) {
				this.Initialized = true;
				$(this).css("padding-top", 0).css("padding-bottom", 0);
				$(this).bind("keyup", ResizeTextarea).bind("focus", ResizeTextarea);
			}
		});

		return this;
	};

})(jQuery);


// initialize all expanding textareas
jQuery(document).ready(function() {
	jQuery("textarea[class*=expandable]").TextAreaExpander();
});

/**
 * jQuery.ScrollTo - Easy element scrolling using jQuery.
 * Copyright (c) 2007-2009 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
 * Dual licensed under MIT and GPL.
 * Date: 5/25/2009
 * @author Ariel Flesler
 * @version 1.4.2
 *
 * http://flesler.blogspot.com/2007/10/jqueryscrollto.html
 */
;(function(d){var k=d.scrollTo=function(a,i,e){d(window).scrollTo(a,i,e)};k.defaults={axis:'xy',duration:parseFloat(d.fn.jquery)>=1.3?0:1};k.window=function(a){return d(window)._scrollable()};d.fn._scrollable=function(){return this.map(function(){var a=this,i=!a.nodeName||d.inArray(a.nodeName.toLowerCase(),['iframe','#document','html','body'])!=-1;if(!i)return a;var e=(a.contentWindow||a).document||a.ownerDocument||a;return d.browser.safari||e.compatMode=='BackCompat'?e.body:e.documentElement})};d.fn.scrollTo=function(n,j,b){if(typeof j=='object'){b=j;j=0}if(typeof b=='function')b={onAfter:b};if(n=='max')n=9e9;b=d.extend({},k.defaults,b);j=j||b.speed||b.duration;b.queue=b.queue&&b.axis.length>1;if(b.queue)j/=2;b.offset=p(b.offset);b.over=p(b.over);return this._scrollable().each(function(){var q=this,r=d(q),f=n,s,g={},u=r.is('html,body');switch(typeof f){case'number':case'string':if(/^([+-]=)?\d+(\.\d+)?(px|%)?$/.test(f)){f=p(f);break}f=d(f,this);case'object':if(f.is||f.style)s=(f=d(f)).offset()}d.each(b.axis.split(''),function(a,i){var e=i=='x'?'Left':'Top',h=e.toLowerCase(),c='scroll'+e,l=q[c],m=k.max(q,i);if(s){g[c]=s[h]+(u?0:l-r.offset()[h]);if(b.margin){g[c]-=parseInt(f.css('margin'+e))||0;g[c]-=parseInt(f.css('border'+e+'Width'))||0}g[c]+=b.offset[h]||0;if(b.over[h])g[c]+=f[i=='x'?'width':'height']()*b.over[h]}else{var o=f[h];g[c]=o.slice&&o.slice(-1)=='%'?parseFloat(o)/100*m:o}if(/^\d+$/.test(g[c]))g[c]=g[c]<=0?0:Math.min(g[c],m);if(!a&&b.queue){if(l!=g[c])t(b.onAfterFirst);delete g[c]}});t(b.onAfter);function t(a){r.animate(g,j,b.easing,a&&function(){a.call(this,n,b)})}}).end()};k.max=function(a,i){var e=i=='x'?'Width':'Height',h='scroll'+e;if(!d(a).is('html,body'))return a[h]-d(a)[e.toLowerCase()]();var c='client'+e,l=a.ownerDocument.documentElement,m=a.ownerDocument.body;return Math.max(l[h],m[h])-Math.min(l[c],m[c])};function p(a){return typeof a=='object'?a:{top:a,left:a}}})(jQuery);
(function($) {
    
    $.timeFormat = function( timestamp ) {
        var time = handleDate( timestamp );
        return time;
    };
    
    $.timeFormatMin = function( timestamp ) {
    	var date = new Date( parseInt( timestamp ) );
    	return date.getDate() + ' tháng ' + months[ date.getMonth() ];
    };
    
    $.timeFormatSolr = function ( timestr )	{
    	timestr = timestr.replace(/[TZ]/g, ' ').trim();
    	var dt = timestr.split(' ');
    	var d = dt[0].split('-');
    	var t = dt[1].split(':');
    	var timestamp = Date.UTC(d[0], d[1]-1, d[2], t[0], t[1], t[2], 0) - 7 * 3600 * 1000;
    	var time = handleDate( timestamp );
    	return time;
    };
    
    function handleDate( timestamp ) {
        var n=new Date(), t, ago = " ";
        if( timestamp ) {
        	t = Math.round( (n.getTime() - timestamp)/60000 );
        	ago += handleSinceDateEndings( t, timestamp );
        } else {
            ago += "";
        }
        return ago;
    }
    
    function handleSinceDateEndings( t, original_timestamp ) {
        var ago = " ", date;
        date = new Date( parseInt( original_timestamp ) );
        if( t <= 1 ) {
            ago += "Vài giây trước";
        } else if( t<60) {
            ago += t + " phút trước";
        } else if( t>= 60 && t<= 120) {
            ago += Math.floor( t / 60 ) + " giờ trước";
        } else if( t<1440 ) {
            ago += Math.floor( t / 60 )  + " giờ trước";
        } else if( t< 2880) {
            ago +=  "1 ngày trước lúc "+ date.getUTCHours()+'h:'+date.getUTCMinutes();
        } else if( t > 2880  && t < 4320 ) {
            ago +=  "2 ngày trước lúc "+ date.getUTCHours()+'h:'+date.getUTCMinutes();
        } else {
            ago += "ngày " + date.getDate() + "-" + months[ date.getMonth() ] + "-"+ (1900+date.getYear()) +" lúc "+ date.getUTCHours()+'h:'+date.getUTCMinutes();
        }
        return ago;
    }
    
    var months = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"];
})(jQuery);

/**
 * Get the ISO week date week number
 */
getWeek = function (date) {
	// Create a copy of this date object
	var target  = new Date(date.valueOf());

	// ISO week date weeks start on monday
	// so correct the day number
	var dayNr   = (date.getDay() + 6) % 7;

	// ISO 8601 states that week 1 is the week
	// with the first thursday of that year.
	// Set the target date to the thursday in the target week
	target.setDate(target.getDate() - dayNr + 3);

	// Store the millisecond value of the target date
	var firstThursday = target.valueOf();

	// Set the target to the first thursday of the year
	// First set the target to january first
	target.setMonth(0, 1);
	// Not a thursday? Correct the date to the next thursday
	if (target.getDay() != 4) {
		target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
	}

	// The weeknumber is the number of weeks between the 
	// first thursday of the year and the thursday in the target week
	return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
}
jQuery.slugify = function(txt) {
	if (txt == undefined) return txt;
	txt = removeAccents(txt.toLowerCase());
	txt = txt.replace(/\s+/g,'-');
	txt = txt.replace(/[^a-zA-Z0-9\-]/g,'').trim('-');
	return txt;
}

function removeAccents(str){
	//remove accented, perhaps there are other simple ways
    str = str.replace(/[áàảãạăắằẳẵặâấầẩẫậ]/g, 'a');
    str = str.replace(/đ/g, 'd');
    str = str.replace(/[éèẻẽẹêếềểễệ]/g, 'e');
    str = str.replace(/[íìỉĩị]/g, 'i');
    str = str.replace(/[óòỏõọôốồổỗộơớờởỡợ]/g, 'o');
    str = str.replace(/[úùủũụưứừửữự]/g, 'u');
    str = str.replace(/[ýỳỷỹỵ]/g, 'y');
    return str;
}
//toottips hien thi o phia duoi pointer
var offsetfromcursorX = 12;
var offsetfromcursorY = 10;
var offsetdivfrompointerX = 10;
var offsetdivfrompointerY = 14;

// neu muon toottip hien thi len phia tren pointer:
//var offsetfromcursorX = -70;
//var offsetfromcursorY = -60;
//var offsetdivfrompointerX = -70;
//var offsetdivfrompointerY = -64;

document.write('<div id="dhtmltooltip"></div>');
document.write('<img id="dhtmlpointer" />');

var ie = document.all;
var ns6 = document.getElementById && !document.all;
var enabletip = false;

if (ie || ns6) var tipobj = document.all ? document.all["dhtmltooltip"] : document.getElementById ? document.getElementById("dhtmltooltip") : "";

var pointerobj = document.all ? document.all["dhtmlpointer"] : document.getElementById ? document.getElementById("dhtmlpointer") : "";

function ietruebody() {
    return (document.compatMode && document.compatMode != "BackCompat") ? document.documentElement : document.body;
}

function showtip(thetext, thewidth, theheight, thecolor) {
    if (ns6 || ie) {
        if (typeof thewidth != "undefined")
            tipobj.style.width = thewidth + "px";
        if (typeof theheight != "undefined")
            tipobj.style.height = theheight + "px";
        if (typeof thecolor != "undefined" && thecolor != "")
            tipobj.style.backgroundColor = thecolor;
        tipobj.innerHTML = thetext;
        enabletip = true;
        return false;
    }
}

function positiontip(e) {
    if (enabletip) {
        var nondefaultpos = false;
        var curX = (ns6) ? e.pageX : event.clientX + ietruebody().scrollLeft;
        var curY = (ns6) ? e.pageY : event.clientY + ietruebody().scrollTop;

        var winwidth = ie && !window.opera ? ietruebody().clientWidth : window.innerWidth - 20;
        var winheight = ie && !window.opera ? ietruebody().clientHeight : window.innerHeight - 20;

        var rightedge = ie && !window.opera ? winwidth - event.clientX - offsetfromcursorX : winwidth - e.clientX - offsetfromcursorX;
        var bottomedge = ie && !window.opera ? winheight - event.clientY - offsetfromcursorY : winheight - e.clientY - offsetfromcursorY;

        var leftedge = (offsetfromcursorX < 0) ? offsetfromcursorX * (-1) : -1000;

        if (rightedge < tipobj.offsetWidth) {
            tipobj.style.left = curX - tipobj.offsetWidth + "px";
            nondefaultpos = true;
        }
        else if (curX < leftedge)
            tipobj.style.left = "5px";
        else {
            tipobj.style.left = curX + offsetfromcursorX - offsetdivfrompointerX + "px";
            pointerobj.style.left = curX + offsetfromcursorX + "px";
        }

        if (bottomedge < tipobj.offsetHeight) {
            tipobj.style.top = curY - tipobj.offsetHeight - offsetfromcursorY + "px";
            nondefaultpos = true;
        }
        else {
            tipobj.style.top = curY + offsetfromcursorY + offsetdivfrompointerY + "px";
            pointerobj.style.top = curY + offsetfromcursorY + "px";
        }

        tipobj.style.visibility = "visible";

        if (!nondefaultpos)
            pointerobj.style.visibility = "visible";
        else
            pointerobj.style.visibility = "hidden";
    }
}

function hidetip() {
    if (ns6 || ie) {
        enabletip = false;
        tipobj.style.visibility = "hidden";
        pointerobj.style.visibility = "hidden";
        tipobj.style.left = "-1000px";
        tipobj.style.backgroundColor = '';
        tipobj.style.width = '';
    }
}

document.onmousemove = positiontip;
/**
 * A class to store system-wide properties
 * @augments Class
 * @author griever
 */
SystemProperty = Class.extend({
	
	/**
	 * Initialize properties
	 * @constructors
	 */
	init: function()	{
		this.properties = Array();
	},
	
	/**
	 * Retrieve the value of a property
	 * @function
	 * @param {property} the name of the property to retrieve
	 * @param {defaultValue} the default value, used if the property is not found
	 * @returns {mixed} the property value, or the default value or undefined 
	 */
	get: function(property, defaultValue)	{
		var cookieValue = $.cookie(property);
		if(cookieValue != undefined){
			return cookieValue;
		}else if(this.properties[property] != undefined){
			return this.properties[property];
		}else {
			return defaultValue;
		}
	},
	
	/**
	 * Store the value of a property
	 * @function
	 * @param {property} the name of the property to store
	 * @param {value} the new value
	 * @param {persistent} should the property be stored in cookie for future use
	 */
	set: function(property, value, persistent)	{
		if(!persistent){
			this.properties[property] = value;
		}else{
			$.cookie(property,value,{ expires: 1 });
		}
//		console.log('system property changed: '+property);
		var subject = SingletonFactory.getInstance(Subject);
		subject.notifyEvent("SystemPropertyChanged", property);
	},
	
	dump: function()	{
		//console.log('Dumping system properties...');
		for(var p in this.properties)	{
			//console.log(p+": "+this.properties[p]);
		}
		//console.log('Dumping complete!');
	}
});

/**
 * Resource Manager. Manage resource using the underlying resource locator
 * @augments Class
 * @author griever
 */
ResourceManager = Class.extend({
	
	/**
	 * Initialize resource locators
	 * @constructors
	 */
	init: function()	{
		this.resourceLocator = new JQueryResourceLocator();
	},
	
	/**
	 * Change the current resource locator
	 * @param {locator} the resource locator to be used
	 */
	setResourceLocator: function(locator)	{
		this.resourceLocator = locator;
	},
	
	/**
	 * Get the current resource locator
	 * @returns {ResourceLocator} the current resource locator
	 */
	getResourceLocator: function(locator)	{
		return this.resourceLocator;
	},
	
	/**
	 * Ask the underlying resource locator for a specific resource
	 * @param {type} used as a namespace to distinct different resources with the same name
	 * @param {name} the name of the resource
	 * @param {resourceLocator} Optional. The resource locator to be used in the current request
	 */
	requestForResource: function(type, name, resourceLocator)	{
		var id = type+"-"+name;
		if (resourceLocator != undefined)	{
			return resourceLocator.locateResource(id);
		}
		return this.resourceLocator.locateResource(id);
	},
	
	/**
	 * Ask the underlying resource locator for a custom resource
	 * @param {customSelector} the selector used to retrieve the resource, depending on underlying the resource locator
	 * @param {resourceLocator} Optional. The resource locator to be used in the current request
	 */
	requestForCustomResource: function(customSelector, resourceLocator)	{
		if (resourceLocator != undefined)	{
			return resourceLocator.locateResource(customSelector);
		}
		return this.resourceLocator.locateCustomResource(customSelector);
	}
});

/**
 * ResourceLocator. Locate resource
 * @augments Class
 * @author griever
 */
ResourceLocator = Class.extend({
	/**
	 * Locate a resource based on its ID
	 * By default, this function do nothing
	 */
	locateResource: function(resourceID)	{
		
	}
});

/**
 * JQuery Resource Locator. Locate resource using DOM
 * @augments ResourceLocator
 * @author griever
 */
JQueryResourceLocator = ResourceLocator.extend({
	
	/**
	 * Locate resource based on its ID
	 * @param {id} the resource ID
	 * @returns {mixed} the resource or undefined
	 */
	locateResource: function(id)	{
		if ($('#'+id).length > 0)	{
			return $('#'+id);
		}
		return undefined;
	},
	
	/**
	 * Locate resource based on the custom selector
	 * @param {custom} the custom selector
	 * @returns {mixed} the resource or undefined
	 */
	locateCustomResource: function(custom)	{
		if ($(custom).length > 0)	{
			return $(custom);
		}
		return undefined;
	}
});

//JQuery Horizontal alignment plugin
(function ($) { $.fn.vAlign = function() { return this.each(function(i){ var h = $(this).height(); var oh = $(this).outerHeight(); var mt = (h + (oh - h)) / 2; $(this).css("margin-top", "-" + mt + "px"); $(this).css("top", "50%"); $(this).css("position", "absolute"); }); }; })(jQuery); (function ($) { $.fn.hAlign = function() { return this.each(function(i){ var w = $(this).width(); var ow = $(this).outerWidth(); var ml = (w + (ow - w)) / 2; $(this).css("margin-left", "-" + ml + "px"); $(this).css("left", "50%"); $(this).css("position", "absolute"); }); }; })(jQuery);

/**
 * Manage a set of objects
 * @augments Class
 * @author griever
 */
ObjectManager = Class.extend({
	
	/**
	 * Initialize fields
	 * @constructor
	 */
	init: function()	{
		this.objects = new Array();
		this.context = null;
		this.mainObjects = new Array();
	},

	/**
	 * Register an object to be managed by this
	 * @function
	 * @param {obj} the object to register
	 */
	register: function(obj)	{
		this.objects.push(obj);
	},
	
	/**
	 * Register a context
	 * @function
	 * @param {obj} the context to register
	 */
	registerContext: function(obj)	{
		this.context = obj;
	},
	
	/**
	 * main object is one visualize the idea, a main object usually is a collection of main image
	 * and other thing support for the display
	 * @function
	 * @param {obj} the main object
	 */
	registerMainObjects: function(obj)	{
		this.mainObjects.push(obj);
	},
	
	/**
	 * Retrieve the main objects
	 * @function
	 * @returns {mixed} the main objects
	 */
	getMainObjects: function(){
		return this.mainObjects;
	},

	/**
	 * Remove object from the list
	 * @function
	 * @param {obj} the object to be removed
	 */
	remove: function(obj)	{
		/*
		* remove from display
		*/
		var i = this.findIndex(obj.id);
		if (i != -1)	{
			this.objects.splice(i, 1);
		}
		/*
		* remove from mainObjects array
		*/
		for(var j=0;j<this.mainObjects.length;j++)	{
			if(obj.id == this.mainObjects[j].id)		{
				this.mainObjects.splice(j,1);
			}
		}
	},
	
	/**
	 * Find an object using its ID
	 * @function
	 * @param {objId} the id of the object to be found
	 * @returns {mixed} the object or undefined
	 */
	find: function(objId)	{
		var i = this.findIndex(objId);
		if (i == -1)
			return undefined;
		return this.objects[i];
	},
	
	/**
	 * Find the index of the object having specific ID
	 * @function
	 * @param {objId} the id of the object to be found
	 * @returns {mixed} the index of the object or -1
	 */
	findIndex: function(objId)	{
		for(var i=0;i<this.objects.length;i++)	{
			if (objId == this.objects[i].id)	{
				return i;
			}
		}
		return -1;
	}
});

/**
 * Entry-point class
 * @augments Class
 */
Application = Class.extend({
	/**
	 * Initialize fields
	 * @constructor
	 */
	init: function()	{
		if(Application.singleton == undefined){
			throw "Singleton class, can not be directly created !";
			return undefined;
		}
		this.systemProperties = new SystemProperty();
		this.resourceManager = new ResourceManager();
	},
	
	/**
	 * Access the application's resource manager
	 * @function
	 * @returns {mixed} the application's resource manager
	 */
	getResourceManager: function()	{
		return this.resourceManager;
	},
	
	/**
	 * Change the application's resource manager
	 * @function
	 * @param {ResourceManager} the resource manager to be used
	 */
	setResourceManager: function(rm)	{
		this.resourceManager = rm;
	},
	
	/**
	 * Get the system properties array
	 * @function
	 * @returns {mixed} the system properties
	 */
	getSystemProperties: function()	{
		return this.systemProperties;
	},
	
	/**
	 * Change the bootstrap of the application
	 * @function
	 * @returns {Bootstrap} the bootstrap of the application
	 */
	setBootstrap: function(bootstrap)	{
		this.bootstrap = bootstrap;
	},
	
	/**
	 * Begin the application. This should be called only once
	 * @function
	 */
	begin: function()	{
		this.bootstrap.run();
	},

	/**
	 * Get the application's object manager
	 * @function
	 * @returns {ObjectManager} the application's object manager
	 */
	getObjectManager: function()	{
		if (this.objMgr == undefined)
			this.objMgr = new ObjectManager();
		return this.objMgr;
	}
});

/**
 * Singleton Factory. Used to access initialize
 */
SingletonFactory = function(){};

SingletonFactory.getInstance = function(classname){
	if(classname.instance == undefined){
		classname.singleton = 0;
		classname.instance = new classname();
		classname.singleton = undefined;
	}
	return classname.instance;
};

/**
 * IMPLEMENTOR & HANDLERS
 */
InterfaceImplementor = Class.extend({
	init: function(){
		this.state = false;
	},

	implement: function(obj)	{
		
	},

	bind: function(obj, handler)	{
		new EventBinder().bindEvent(obj, handler);
	}
});

Handler = Class.extend({
	init: function(){
		
	},
	
	getEventName: function()	{
		return "";
	},
	
	onEvent: function(e)	{
		
	}
});

/**
 * Wrap the jquery object with our DisplayObject
 * In the future it will add classes, bind events... as well
 */
JQueryWrapper = Class.extend({
	init: function(obj, id)	{
		obj.id = id;
		this.obj = obj;
	},
	
	getWrappedObject: function()	{
		return this.obj;
	}
});
/**
 * Base displayable object
 */
DisplayObject = Class.extend	({
	init: function()	{
		var app = SingletonFactory.getInstance(Application);
		this.id=0;
		this.type = "default";
		this.htmlClasses = new Array();
		this.interfaces = new Array();
		var objMgr = app.getObjectManager();
		this.className = "DisplayObject";
		objMgr.register(this);
	},
	
	addEventHandler: function(eventHandler)	{
		new EventBinder().bindEvent(this, eventHandler);
	},
	
	deserializeStyle: function(style)	{
		this.deserializedStyle = style;
	},
	
	serializeStyle: function()	{
		return this.getAttribute('style');
	},
	
	serialize: function()	{
		var obj = {};
		obj.className = this.className;
		return obj;
	},
	
	getPosition: function()	{
		return this.access().offset();
	},
	
	moveTo: function(top, left)	{
		this.access().css('left', left+"px");
		this.access().css('top', top+"px");
	},
	
	center: function()	{
		this.access().hAlign();
		this.access().vAlign();
	},
	
	moveToBR: function(bottom, right)	{
		this.access().css('bottom', bottom+"px");
		this.access().css('right', right+"px");
	},

	getType: function()	{
		return "ij-"+this.type;
	},

	toHtml: function()	{
		return "";
	},
	
	getParent: function()	{
		return this.parent;
	},
	
	setParent: function(parent)	{
		if (this.parent != undefined)	{
			this.parent.detachObject(this);
		}
		this.parent = parent;
	},
	
	getId: function()	{
		return this.id;
	},
	
	access: function()	{
		return $('#'+this.id);
	},
	
	resizeTo: function(width, height)	{
		this.access().css('width', width+"px");
		this.access().css('height', height+"px");
	},
	
	getDimension: function()	{
		var dim = {};
		dim.width = this.access().width();
		dim.height = this.access().height();
		return dim;
	},
	
	setStyle: function(styleName, value)	{
		this.access().css(styleName, value);
	},
	
	setAttribute: function(attrName, value)	{
		this.access().attr(attrName, value);
	},
	
	getAttribute: function(attrName)	{
		return this.access().attr(attrName);
	},
	
	implement: function(implementor)	{
		if($("#"+this.getId()).length > 0){
			implementor.implement(this);
			implementor.state = true;
		}
		this.interfaces.push(implementor);
		this.updateInterfaces();
	},
	
	addClass: function(className)	{
		this.htmlClasses.push(className);
		this.updateClasses();
	},
	
	getHtmlClasses: function()	{
		return this.htmlClasses;
	},
	
	show: function()	{
		this.access().show();
	},
	
	hide: function()	{
		this.access().hide();
	},
	
	dispose: function()	{
		var app = SingletonFactory.getInstance(Application);
		this.access().remove();
		app.getObjectManager().remove(this);
	},
	
	updateClasses: function()	{
		var classes = this.getHtmlClasses();
		var classNames = this.getType();
		for(var i=0;i<classes.length;i++)	{
			classNames+= " "+classes[i];
		}
		this.access().attr('class', classNames);
	},
	
	updateInterfaces: function()	{
		var interfaces = this.interfaces;
		for(var i=0;i<interfaces.length;i++)	{
			var implementor = interfaces[i];
			if (implementor != null && !implementor.state && $("#"+this.getId()).length > 0)	{
				implementor.implement(this);
				implementor.state = true;
			}
		}
	},
	
	afterLoad: function()	{
		this.setAttribute('style', this.deserializedStyle);
	},
	
	/**
	 * Update HTML element when properties are changed
	 */
	update: function()	{
		this.updateClasses();
		this.updateInterfaces();
	},
	
	afterCreate: function()	{
		this.update();
		new EventBinder().fireEvent(this.access(), 'object_created');
	}
});

/**
 * Container class. A container is an object which 'contains' other objects
 */
Container = DisplayObject.extend({
	init: function()	{
		this._super();
		this.objects = new Array();
		this.type = "container";
		this.className = "Container";
	},
	
	addObjectBeforePosition: function(obj, positionObj)	{
		this.objects.push(obj);
		//this.access().append(obj.toHtml());
		if($("#"+obj.access().attr("id")).length == 0){
			//console.log("Not existed before !, id: "+obj.access().attr("id"));
			$(positionObj).before(obj.toHtml());
		}else{
			//console.log("Just move !");
			obj.access().detach();
			obj.access().insertBefore(positionObj);
		}
		obj.setParent(this);
		obj.afterCreate();
	},
	
	addObject: function(obj)	{
		this.objects.push(obj);
		//this.access().append(obj.toHtml());
		if($("#"+obj.access().attr("id")).length == 0){
			//console.log("Not existed before !, id: "+obj.access().attr("id"));
			this.access().append(obj.toHtml());
		}else{
			//console.log("Just move !");
			obj.access().detach();
			obj.access().appendTo(this.access());
		}
		obj.setParent(this);
		obj.afterCreate();
	},
	
	afterCreate: function(obj)	{
		this._super();
		for(var i=0;i<this.objects.length;i++)	{
			this.objects[i].afterCreate();
		}
	},
	
	removeObject: function(object)	{
		for(var i=0;i<this.objects.length;i++)	{
			var obj = this.objects[i];
			if (obj.getId() == object.getId())	{
				this.objects.splice(i, 1);
				object.dispose();
			}
		}
	},
	
	detachObject: function(object)	{
		for(var i=0;i<this.objects.length;i++)	{
			var obj = this.objects[i];
			if (obj.getId() == object.getId())	{
				this.objects.splice(i, 1);
			}
		}
	},
	
	getObjects: function()	{
		return this.objects;
	},
	
	toHtml: function()	{
		var html = "";
		for(var i=0;i<this.objects.length;i++)	{
			html += this.objects[i].toHtml();
		}
		return html;
	}
});

Canvas = Container.extend({
	init: function()	{
		this._super();
		// FIXME: Store this list in another location?
		this.type = "canvas";
		this.id = generateId('canvas');
		this.className = "Canvas";
	},

	toHtml: function()	{
		return "<div id='"+this.id+"'>"+this._super()+"</div>";
	}
});

PrebuiltCanvas = Canvas.extend({
	init: function(id)	{
		this._super();
		this.id = id;
	},
	
	appendObject: function(object)	{
		this.access().append(object.access());
	}
});

/*
 * Font
 */
Font = Class.extend({
	init:function()	{
		this.fontFamily = 'Tahoma,sans-serif';
		this.fontSize = "12px";
		this.bold = false;
		this.italic = false;
		this.color = "#000000";
	},
	
	setFont: function(fontFamily, fontSize, bold, italic, color)	{
		this.fontFamily = fontFamily;
		this.fontSize = fontSize;
		this.bold = bold;
		this.italic = italic;
		this.color = color;
	},
	
	setFontFamily: function(fontFamily)	{
		this.fontFamily = fontFamily;
	},
	
	getFontFamily: function()	{
		return this.fontFamily;
	},
	
	setFontSize: function(fontSize)	{
		this.fontSize = fontSize;
	},
	
	getFontSize: function()	{
		return this.fontSize;
	},
	
	setBold: function(bold)	{
		this.bold = bold;
	},
	
	getBold: function()	{
		return this.bold;
	},
	
	setItalic: function(italic)	{
		this.italic = italic;
	},
	
	getItalic: function()	{
		return this.italic;
	},
	
	setColor: function(color)	{
		this.color = color;
	},
	
	getColor: function()	{
		return this.color;
	}
});
/**
 * Image object
 */
ImageObject = DisplayObject.extend	({
	
	init: function(src)	{
		this._super();
		if (!src.match("http://") && !src.match("https://")){
			config = new Config();
			this.src = config.getRoot()+src;
		}else{
			this.src = src;
		}
		this.id = generateId('image');
		this.type = "Image";
		this.zIndex = 1000;
		this.className = "ImageObject";
	},
	
	toHtml: function()	{
		return "<img id='"+this.id+"' src='"+this.src+"' ></img>";
	},
	
	getSrc: function()	{
		return this.src;
	}
});

/**
 * Rotatable
 */
RotatableImage = ImageObject.extend({
	init: function(src)	{
		this._super(src);
		this.prevrotation = 0;
		this.className = "RotatableImage";
	},
	
	setPrevRotation: function(rot){
		if (rot > 180){
			rot = rot - 180;
		}
		if (rot < -180){
			rot = rot + 180;
		}
		this.prevrotation = rot;
	},
	
	getPrevRotation: function(){
		return this.prevrotation;
	},
	
	rotate: function(e)	{
		var parent = this.getParent();
		var left = this.getPosition().left;
		var top = this.getPosition().top;
		
		var h = top - parent.baseDotTL.getPosition().top - 7;
		var w = left - parent.baseDotTL.getPosition().left - 7;
		
		var rad = Math.atan2(h, w);
		var deg = Math.round(rad*180/Math.PI);
		parent.access().css('-moz-transform', 'rotate('+deg+'deg)');
		parent.access().css('-webkit-transform', 'rotate('+deg+'deg)');
		parent.access().css('transform', 'rotate('+deg+'deg)');
	}
});


/**
 * Textbox
 */
TextArea = DisplayObject.extend	({
	
	init: function(txt)	{
		this._super();
		this.font = new Font();
		this.txt = txt;
		this.id = generateId('textarea');
		this.type = "TextArea";
		this.implement(new ClickTextAreaStopEvent());
		this.implement(new BlurTextAreaUpdate());
		this.className = "TextArea";
	},
	
	toHtml: function()	{
		return "<textarea id='"+this.id+"' value='"+this.txt+"'></textarea>";
	},
		
	getText: function()	{
		return this.access().val();
	},
	
	getFont: function(){
		return this.font;
	},
	
	setFont: function(font){
		this.font = font;
	},
	
	updateText: function()	{
		this.parent.updateText(this.getText(),this.getFont());
		this.hide();
	},
	
	focus: function()	{
		this.access().focus();
	}
});

/**
 * Label
 */
Label = DisplayObject.extend	({
	
	init: function(txt)	{
		this._super();
		this.txt = txt;
		this.id = generateId('text');
		this.type = "Label";
		this.className = "Label";
	},
	
	toHtml: function()	{
		return "<label id='"+this.id+"' value='"+this.txt+"'></label>";
	},
		
	getText: function()	{
		return this.access().html();
	},
	
	setText: function(txt,font)	{
		if(font==null){
			this.access().html(txt);
		}else{
			var text = txt;
			var fontText = "font-family: "+font.getFontFamily()+"; font-size:"+font.getFontSize();
			fontText += "; color:"+font.getColor();
			if(font.getItalic()){
				fontText += ";font-style:italic";
			}else{
				fontText += ";font-style:normal";
			}
			if(font.getBold()){
				fontText += ";font-weight:bold";
			}
			text = "<span style='"+fontText+"'>"+text+"</span>";
			this.access().html(text);
		}
	}
});

/*
* ContextMenu class. A context menu is trigger by the right click, holding many contextMenuItem
*/
ContextMenu = Canvas.extend({
	init: function()	{
		this._super();
		this.items = new Array();
		this.type = 'contextmenu';
		this.className = "ContextMenu";
	},
	
	addItem: function(item){
		this.items.push(item);
		this.addObject(item);
		this.update();
	},
	
	afterCreate: function(){
		this._super();
		this.setStyle('zIndex','1000');
		this.update();
	}
});

/*
* ContextMenuItem class. A context menu item is an item binding to events
*/
ContextMenuItem = Canvas.extend({
	init: function(lbl,obj)	{
		this._super();
		this.label_txt = lbl;
		this.label = new Label('');
		this.addObject(this.label);		
		this.type = "contextmenuitem";
		this.originObject = obj;
		this.className = "ContextMenuItem";
	},
	
	afterCreate: function(){
		this.label.setText(this.label_txt);
		this.update();
	},
	
	setOriginObject: function(obj)	{
		this.originObject = obj;
	},
	
	getOriginObject: function()	{
		return this.originObject;
	}
});

DraggableWrapper = Class.extend({
	wrap: function(obj)	{
		obj.access().draggable();
		obj.access().css('position','absolute');
		return obj;
	}
});

ImageIconWrapper = Class.extend	({
	wrap: function(img)	{
		img.addClass("icon");
		return img;
	}
});

ClickableImageWrapper = Class.extend({
	wrap: function(img)	{
		img.implement(new ClickIcon());
		return img;
	}
});

ImageBox = Canvas.extend({
	init: function(src)	{
		this._super();
		this.src = src;
		this.img = new Image(src);
		this.baseDotTL = new Image('images/delete-small.png');
		this.resizeDotBR = new Image('images/sq.png');
		this.dummyDotTR = new Image('images/sq.png');
		this.dummyDotBL = new Image('images/sq.png');
		this.rotateIcon = new RotatableImage('images/sq.png');
		this.textArea = new TextArea('');
		this.text = new Label('');

		this.addObject(this.resizeDotBR);
		this.addObject(this.baseDotTL);
		this.addObject(this.dummyDotTR);
		this.addObject(this.dummyDotBL);
		this.addObject(this.rotateIcon);
		this.addObject(this.textArea);
		this.addObject(this.text);
		this.addObject(this.img);
		this.type = "imagebox";
		this.className = "ImageBox";
		
		app.getObjectManager().registerMainObjects(this);
	},
	
	getTextArea: function()	{
		return this.textArea;
	},
	
	getZIndex: function()	{
		if(this.zIndex == null){
			this.zIndex = this.access().css("z-index");
		}
		if(this.zIndex == null){
			this.zIndex = 1000;
		}
		return this.zIndex;
	},
	
	setZIndex: function(index)	{
		this.zIndex = index;
		this.setStyle("z-index",this.zIndex);
		this.update();
	},
	
	showTextArea: function()	{
		this.text.hide();
		this.textArea.show();
		this.textArea.focus();
	},
	
	showPlainText: function()	{
		this.textArea.hide();
		this.text.show();
		this.text.center();
	},
	
	afterCreate: function()	{
		this._super();
		
		this.resizeDotBR.implement(new ResizableBR());
		this.rotateIcon.implement(new Rotatable());
		this.dummyDotTR.implement(new ResizableTR());
		this.dummyDotBL.implement(new ResizableBL());
		this.baseDotTL.implement(new DeleteImageBox());
		
		this.img.addClass('img-item');
		this.img.setStyle('height', '50px');
		
		var d = new DraggableWrapper();
		d.wrap(this);
		d.wrap(this.resizeDotBR);
		d.wrap(this.rotateIcon);
		d.wrap(this.dummyDotTR);
		d.wrap(this.dummyDotBL);
		
		this.baseDotTL.addClass('sq');
		this.resizeDotBR.addClass('sq');
		this.dummyDotTR.addClass('sq');
		this.dummyDotBL.addClass('sq');
		this.rotateIcon.addClass('sq');
		
		this.updateImages();

		this.implement(new DragSelectImageBox());
		this.implement(new ClickImageBox());
		this.implement(new ClickImageCreateText());
		this.implement(new CreateImageBoxContextMenu());
		this.showPlainText();
		this.baseDotTL.setStyle('position','absolute');
	},
	
	updateText: function(txt,font)	{
		this.text.setText(txt,font);
		this.showPlainText();
	},
	
	updateImages: function()	{
		var dim = this.img.getDimension();
		this.resizeTo(dim.width, dim.height);
		// move base dot & resize dot to top-left and bottom-right respectively
		// and relatively
		var x0 = -11;
		var y0 = -11;
		var x1 = dim.width-5;
		var y1 = dim.height-5;
		
		this.baseDotTL.moveTo(y0, x0);		
		this.resizeDotBR.moveTo(y1-5, x1-5);
		this.dummyDotTR.moveTo(y0, x1);
		this.dummyDotBL.moveTo(y1, x0);
		this.rotateIcon.moveTo(y1/2-10, x1+10);
	},
	
	select: function()	{
		this.baseDotTL.show();
		this.resizeDotBR.show();
		this.dummyDotTR.show();
		this.dummyDotBL.show();
		this.rotateIcon.show();
	},
	
	deselect: function()	{
		this.baseDotTL.hide();
		this.resizeDotBR.hide();
		this.dummyDotTR.hide();
		this.dummyDotBL.hide();
		this.rotateIcon.hide();
	},
	
	deserializeText: function(txt,fontData)	{
		this.getTextArea().txt = txt;
		var f = new Font();
		f.setFont(fontData.fontFamily, fontData.fontSize, fontData.bold, fontData.italic, fontData.color);
		this.getTextArea().setFont(f);
	},
	
	serialize: function()	{
		var obj = this._super();
		obj.params = {};
		obj.params.src = this.src;
		obj.params.style = this.serializeStyle();
		obj.params.txt = this.getTextArea().getText();
		obj.params.font = this.getTextArea().getFont();
		return obj;
	},
	
	afterLoad: function()	{
		this._super();
		this.img.resizeTo(this.getDimension().width, this.getDimension().height);
		this.updateImages();
		this.getTextArea().access().val(this.getTextArea().txt);
		this.updateText(this.getTextArea().getText(), this.getTextArea().getFont());
	}
});

Deserializer = Class.extend({
	deserialize: function(serialized)	{
		if (serialized.className == "ImageBox")	{
			var imageBox = new ImageBox(serialized.params.src);
			imageBox.deserializeStyle(serialized.params.style);
			imageBox.deserializeText(serialized.params.txt,serialized.params.font);
			return imageBox;
		}
	}
});

Button = DisplayObject.extend({
	init: function(txt)	{
		this._super();
		this.txt = txt;
		this.id = generateId('button');
		this.type = "Button";
		this.className = "Button";
	},
	
	toHtml: function()	{
		return "<button id='"+this.id+"' class='"+this.getType()+"'>"+this.txt+"</button>";
	}
});

ToggleButton = DisplayObject.extend({
	init: function(txt,state)	{
		this._super();
		this.txt = txt;
		this.id = generateId('togglebutton');
		this.type = "togglebutton";
		this.className = "ToggleButton";
		this.state = state;
		this.implement(new ClickToggleButton());
	},
	
	afterCreate: function(){
		this._super();
		if(this.state){
			this.addClass("toggledown");
		}
	},
	
	toHtml: function()	{
		return "<a id='"+this.id+"' class='"+this.getType()+"'>"+this.txt+"</a>";
	}
});

/*
* IconSet class. An icon set is a group of icons, grouped by a label which can perform accordion behaviour.
*/

IconSet = Canvas.extend({
	init: function(lbl)	{
		this._super();
		this.lblText = lbl;
		this.container = new Canvas();
		this.header = new Canvas();
		this.label =  new Label('');
		this.header.addObject(this.label);
		this.addObject(this.header);
		this.addObject(this.container);
	},
	
	afterCreate: function()	{
		this.label.addClass('ij-iconsetlbl');
		this.label.setText(this.lblText);
		this.setStyle('position','relative');
		this.header.setStyle('width',(this.access().width()+10)+"px");
		this.header.addClass('ij-headericonset');
		this.container.addClass('ij-containericonset');
		this.header.implement(new ClickHeaderIconSet());
	},
	
	addIcon: function(img){
		img = new ImageIconWrapper().wrap(img);
		img = new ClickableImageWrapper().wrap(img);
		this.container.addObject(img);
	}
});

ToolBox = Canvas.extend({
	init: function()	{
		this._super();
		// FIXME: Store this list in another location?
		this.type = "toolbox";
		this.id = "tool";
		this.addClass("tool");
		this.iconSets = new Array();
	},

	addIcon: function(img)	{
		img = new ImageIconWrapper().wrap(img);
		img = new ClickableImageWrapper().wrap(img);
		this.addObject(img);
	},
	
	addIconSet: function(lbl)	{
		iconset = new IconSet(lbl);
		this.iconSets.push(iconset);
		this.addObject(iconset);
	},
	
	addIconToSet: function(id,img)	{
		this.iconSets[id].addIcon(img);
	}
});

/**
 * IMPLEMENTOR & HANDLERS
 */

ClickImageBox = InterfaceImplementor.extend({
	implement: function(obj)	{
		this.bind(obj, new ClickImageBoxHandler());
	}
});

ClickImageBoxHandler = Handler.extend({
	getEventName: function()	{
		return "click";
	},
	
	onEvent: function(e, obj)	{
		app.select(obj);
		e.stopPropagation();
	}
});

ResizableTR = InterfaceImplementor.extend({
	implement: function(obj)	{
		this.bind(obj, new ResizableTRDragHandler());
		this.bind(obj, new ResizableDragStopHandler());
		this.bind(obj, new MouseOverSqHandler("tr"));
		this.bind(obj, new MouseOutSqHandler("tr"));
	}
});

ResizableTRDragHandler = Handler.extend({
	getEventName: function()	{
		return "drag";
	},
	
	onEvent: function(e, obj)	{		
		var parent = obj.getParent();
		var left = obj.getPosition().left;
		var min = 50;
		var w = left - parent.baseDotTL.getPosition().left - 7;
		var h = parent.access().height();
		if (w < min)	{
			obj.setStyle('left', min);
			obj.access().draggable('disable');
			w = min;
		}
		parent.img.resizeTo(w, h);
		parent.updateImages();
	}
});

ResizableBL = InterfaceImplementor.extend({
	implement: function(obj)	{
		this.bind(obj, new ResizableBLDragHandler());
		this.bind(obj, new ResizableDragStopHandler());
		this.bind(obj, new MouseOverSqHandler("bl"));
		this.bind(obj, new MouseOutSqHandler("bl"));		
	}
});

ResizableBLDragHandler = Handler.extend({
	getEventName: function()	{
		return "drag";
	},
	
	onEvent: function(e, obj)	{		
		var parent = obj.getParent();
		var top = obj.getPosition().top;
		var min = 50;
		var w = parent.access().width();
		var h = top - parent.baseDotTL.getPosition().top - 7;
		if (h < min)	{
			obj.setStyle('left', min);
			obj.access().draggable('disable');
			h = min;
		}
		parent.img.resizeTo(w, h);
		parent.updateImages();
	}
});


ResizableBR = InterfaceImplementor.extend({
	implement: function(obj)	{
		this.bind(obj, new ResizableBRDragHandler());
		this.bind(obj, new ResizableDragStopHandler());
		this.bind(obj, new MouseOverSqHandler("br"));
		this.bind(obj, new MouseOutSqHandler("br"));		
	}
});

ResizableDragStopHandler = Handler.extend({
	getEventName: function()	{
		return "dragstop";
	},

	onEvent: function(e, obj)	{
		obj.access().draggable('enable');
		obj.getParent().updateImages();
	}
});

ResizableBRDragHandler = Handler.extend({
	getEventName: function()	{
		return "drag";
	},

	onEvent: function(e, obj)	{
		var parent = obj.getParent();
		var left = obj.getPosition().left;
		var top = obj.getPosition().top;
		
		var min = 50;
		var h = top - parent.baseDotTL.getPosition().top - 7;
		var w = left - parent.baseDotTL.getPosition().left - 7;
		if (h < min)	{
			obj.setStyle('top', min);
			obj.access().draggable('disable');
			h = min;
		}
		
		if (w < min)	{
			obj.setStyle('left', min);
			obj.access().draggable('disable');
			w = min;
		}
		
		parent.img.resizeTo(w, h);
		parent.updateImages();
	}
});

MouseOverSqHandler = Handler.extend({
	init: function(type)	{
		this.type = type;
	},

	getEventName: function()	{
		return "mouseover";
	},
	
	onEvent: function(e, obj)	{
		var styleName = "sq"+this.type;
		obj.access().addClass("sqhover");
		obj.access().addClass(styleName);
	}
});

MouseOutSqHandler = Handler.extend({
	init: function(type)	{
		this.type = type;
	},

	getEventName: function()	{
		return "mouseout";
	},
	
	onEvent: function(e, obj)	{
		styleName = "sq"+this.type;
		obj.access().removeClass("sqhover");
		obj.access().removeClass(styleName);
	}
});

DragSelectImageBox = InterfaceImplementor.extend({
	implement: function(obj)	{
		this.bind(obj, new DragSelectImageBoxHandler());
// this.bind(obj, new DragStopImageBoxHandler());
	}
});

DragStopImageBoxHandler = Handler.extend({
	getEventName: function()	{
		return "dragstop";
	},
	
	onEvent: function(e, obj)	{
		app.select(obj);
	}
});

DragSelectImageBoxHandler = Handler.extend({
	getEventName: function()	{
		return "drag";
	},
	
	onEvent: function(e, obj)	{
		app.select(obj);
// obj.deselect();
	}
});

ClickIcon = InterfaceImplementor.extend({
	implement: function(obj)	{
		this.bind(obj, new ClickIconHandler());
	}
});

ClickIconHandler = Handler.extend({
	getEventName: function()	{
		return "click";
	},
	
	onEvent: function(e, obj)	{
		var main = app.getMainArea();
		var toolBox = app.getToolBox();
		var item = new ImageBox(obj.getSrc());
		var i = 0;
		main.addObject(item);
		
		item.addClass('item');
		item.moveTo(toolBox.getPosition().top, 600);
		app.select(item);
		
		items = main.getObjects();
		i = items.length;
		items[i] = i;
		item.setZIndex(i);
		item.setAttribute('state','silent');
	}
});

ClickImageCreateText = InterfaceImplementor.extend({
	implement: function(obj)	{
		this.bind(obj, new ClickImageCreateTextHandler());
	}
});

ClickImageCreateTextHandler = Handler.extend({
	getEventName: function()	{
		return "dblclick";
	},
	
	onEvent: function(e, obj)	{
		obj.showTextArea();
	}
});

ClickTextAreaStopEvent = InterfaceImplementor.extend({
	implement: function(obj)	{
		this.bind(obj, new ClickTextAreaStopEventHandler());
	}
});

ClickTextAreaStopEventHandler = Handler.extend({
	getEventName: function()	{
		return "click";
	},
	
	onEvent: function(e, obj)	{
		e.stopPropagation();
	}
});

BlurTextAreaUpdate = InterfaceImplementor.extend({
	implement: function(obj)	{
		this.bind(obj, new BlurTextAreaUpdateHandler());
	}
});
	
BlurTextAreaUpdateHandler = Handler.extend({
	getEventName: function()	{
		return "blur";
	},
	
	onEvent: function(e, obj)	{
		obj.updateText();
	}
});

ClickCanvasDeselect = InterfaceImplementor.extend({
	implement: function(obj)	{
		this.bind(obj, new ClickCanvasDeselectHandler());
	}
});
	
ClickCanvasDeselectHandler = Handler.extend({
	getEventName: function()	{
		return "click";
	},
	
	onEvent: function(e, obj)	{
		app.deselect();
	}
});

Rotatable = InterfaceImplementor.extend({
	implement: function(obj)	{
		this.bind(obj, new RotateMouseMove());
		this.bind(obj, new RotateStop());
	}
});

RotateStop = Handler.extend({
	getEventName: function()	{
		return "dragstop";
	},

	onEvent: function(e, obj)	{
		obj.getParent().updateImages();
	}
});

RotateMouseMove = Handler.extend({
	getEventName: function()	{
		return "drag";
	},

	onEvent: function(e, obj)	{
		obj.rotate(e);
	}
});

ClickAlert = InterfaceImplementor.extend({
	implement: function(obj)	{
		this.bind(obj, new ClickAlertHandler());
	}
});

ClickAlertHandler = Handler.extend({
	getEventName: function()	{
		return "click";
	},

	onEvent: function(e, obj)	{
		alert('hello');
	}
});

DeleteImageBox = InterfaceImplementor.extend({
	implement: function(obj)	{
		this.bind(obj, new DeleteImageBoxHandler());
		this.bind(obj, new MouseOverSqHandler("tl"));
		this.bind(obj, new MouseOutSqHandler("tl"));	
	}
});

DeleteImageBoxHandler = Handler.extend({
	getEventName: function()	{
		return "click";
	},
	
	onEvent: function(e, obj)	{
		obj.parent.dispose();
	}
});

ClickExportJPG = InterfaceImplementor.extend({
	implement: function(obj)	{
		this.bind(obj, new ClickExportJPGHandler());
	}
});

ClickExportJPGHandler = Handler.extend({
	getEventName: function()	{
		return "click";
	},
	
	onEvent: function(e, obj)	{
		toimg();
	}
});

ClickHeaderIconSet = InterfaceImplementor.extend({
	implement: function(obj)	{
		this.bind(obj, new ClickHeaderIconSetHandler());
	}
});

ClickHeaderIconSetHandler = Handler.extend({
	getEventName: function()	{
		return "click";
	},
	
	onEvent: function (e, obj)	{
		obj.parent.container.access().toggle();
	}
});

CreateImageBoxContextMenu = InterfaceImplementor.extend({
	implement: function(obj)	{
		this.bind(obj, new CreateImageBoxContextMenuHandler());
	}
});

CreateImageBoxContextMenuHandler = InterfaceImplementor.extend({
	getEventName: function()	{
		return "contextmenu";
	},
	
	onEvent: function (e, obj)	{
		e.preventDefault();
		if(app.getObjectManager().context != null){
			app.getObjectManager().context.dispose();
		}
		var contextMenu = new ContextMenu();
		var moveToBack = new ContextMenuItem('Move to back',obj);
		var moveBackward = new ContextMenuItem('Move backward',obj);
		var moveToFront = new ContextMenuItem('Move to front',obj);
		var moveForward = new ContextMenuItem('Move forward',obj);
		var properties = new ContextMenuItem('Properties',obj);
		var zIndex = new ContextMenuItem('Z-index',obj);
		var main = app.getMainArea();
		var _top = e.pageY;
		var _left = e.pageX;		
				
		properties.implement(new EventPropertiesContextMenu());
		zIndex.implement(new EventZIndexContextMenu());
		moveToBack.implement(new EventMoveToBackContextMenu());
		moveBackward.implement(new EventMoveBackwardContextMenu());
		moveToFront.implement(new EventMoveToFrontContextMenu());		
		moveForward.implement(new EventMoveForwardContextMenu());

		contextMenu.addItem(moveToBack);
		contextMenu.addItem(moveToFront);
		contextMenu.addItem(moveBackward);
		contextMenu.addItem(moveForward);
		contextMenu.addItem(zIndex);
		contextMenu.addItem(properties);
		
		main.addObject(contextMenu);
		contextMenu.setStyle('top',_top);
		contextMenu.setStyle('left',_left);
		objMgr = app.getObjectManager().registerContext(contextMenu);
	}
});

EventMoveToBackContextMenu = InterfaceImplementor.extend({
	implement: function(obj)	{
		this.bind(obj, new ClickMoveToBackContextMenuHandler());
		this.bind(obj, new MouseOverContextMenuItemHandler());
		this.bind(obj, new MouseOutContextMenuItemHandler());
	}
});

ClickMoveToBackContextMenuHandler = Handler.extend({
	getEventName: function(){
		return "click";
	},
	
	onEvent: function(e,obj){
		var objManager = app.getObjectManager();
		var obj = obj.getOriginObject();
		var thisZIndex = obj.getZIndex();
		var indexArr = new Array();
		var mainObjects = objManager.getMainObjects();
		for(var i=0;i<mainObjects.length;i++){
			indexArr.push(mainObjects[i].getZIndex());
		}
		var minIndex = Array.min(indexArr);
		if(minIndex == thisZIndex){
			return;
		}else{
			for(var i=0;i<mainObjects.length;i++){
				if(mainObjects[i].getZIndex() < thisZIndex){
					mainObjects[i].setZIndex(Array.nextBigger(indexArr,mainObjects[i].getZIndex()));
				}
			}
			obj.setZIndex(minIndex);
		}
		/*
		* update display
		*/
		for(var i=0;i<mainObjects.length;i++){
			mainObjects[i].update();
		}
	}
});

EventMoveToFrontContextMenu = InterfaceImplementor.extend({
	implement: function(obj)	{
		this.bind(obj, new ClickMoveToFrontContextMenuHandler());
		this.bind(obj, new MouseOverContextMenuItemHandler());
		this.bind(obj, new MouseOutContextMenuItemHandler());
	}
});

ClickMoveToFrontContextMenuHandler = Handler.extend({
	getEventName: function(){
		return "click";
	},
	
	onEvent: function(e,obj){
		var objManager = app.getObjectManager();
		var obj = obj.getOriginObject();
		var thisZIndex = obj.getZIndex();
		var indexArr = new Array();
		var mainObjects = objManager.getMainObjects();
		for(var i=0;i<mainObjects.length;i++){
			indexArr.push(mainObjects[i].getZIndex());
		}
		var maxIndex = Array.max(indexArr);
		if(maxIndex == thisZIndex){
			return;
		}else{
			for(var i=0;i<mainObjects.length;i++){
				if(mainObjects[i].getZIndex() > thisZIndex){
					mainObjects[i].setZIndex(Array.nextLess(indexArr,mainObjects[i].getZIndex()));
				}
			}
			obj.setZIndex(maxIndex);
		}
		/*
		* update display
		*/
		for(var i=0;i<mainObjects.length;i++){
			mainObjects[i].update();
		}	}
});

EventMoveBackwardContextMenu = InterfaceImplementor.extend({
	implement: function(obj)	{
		this.bind(obj, new ClickMoveBackwardContextMenuHandler());
		this.bind(obj, new MouseOverContextMenuItemHandler());
		this.bind(obj, new MouseOutContextMenuItemHandler());
	}
});

ClickMoveBackwardContextMenuHandler = Handler.extend({
	getEventName: function(){
		return "click";
	},
	
	onEvent: function(e,obj){
		var objManager = app.getObjectManager();
		var obj = obj.getOriginObject();
		var thisZIndex = obj.getZIndex();
		var indexArr = new Array();
		var mainObjects = objManager.getMainObjects();
		for(var i=0;i<mainObjects.length;i++){
			indexArr.push(mainObjects[i].getZIndex());
		}
		var minIndex = Array.min(indexArr);
		var id = -1;
		if(minIndex == thisZIndex){
			return;
		}else{
			minIndex = -1;
			for(var i=0;i<mainObjects.length;i++){
				if(mainObjects[i].getZIndex() < thisZIndex && mainObjects[i].getZIndex() > minIndex){
					minIndex = mainObjects[i].getZIndex();
					id = i;
				}
			}
			mainObjects[id].setZIndex(thisZIndex);
			obj.setZIndex(minIndex);
		}
		app.select(obj);
		for(var i=0;i<mainObjects.length;i++){
			mainObjects[i].update();
		}
	}
});

EventMoveForwardContextMenu = InterfaceImplementor.extend({
	implement: function(obj)	{
		this.bind(obj, new ClickMoveForwardContextMenuHandler());
		this.bind(obj, new MouseOverContextMenuItemHandler());
		this.bind(obj, new MouseOutContextMenuItemHandler());
	}
});

ClickMoveForwardContextMenuHandler = Handler.extend({
	getEventName: function(){
		return "click";
	},
	
	onEvent: function(e,obj){
		var objManager = app.getObjectManager();
		var obj = obj.getOriginObject();
		var thisZIndex = obj.getZIndex();
		var indexArr = new Array();
		var mainObjects = objManager.getMainObjects();
		for(var i=0;i<mainObjects.length;i++){
			indexArr.push(mainObjects[i].getZIndex());
		}
		var maxIndex = Array.max(indexArr);
		var id = -1;
		if(maxIndex == thisZIndex){
			return;
		}else{
			maxIndex = 1000;
			for(var i=0;i<mainObjects.length;i++){
				if(mainObjects[i].getZIndex() > thisZIndex && mainObjects[i].getZIndex() < maxIndex){
					maxIndex = mainObjects[i].getZIndex();
					id = i;
				}
			}
			mainObjects[id].setZIndex(thisZIndex);
			obj.setZIndex(maxIndex);
		}
		app.select(obj);
		for(var i=0;i<mainObjects.length;i++){
			mainObjects[i].update();
		}
	}
});

EventZIndexContextMenu = InterfaceImplementor.extend({
	implement: function(obj)	{
		//this.bind(obj, new ClickPropertiesContextMenuHandler());
		this.bind(obj, new MouseOverContextMenuItemHandler());
		this.bind(obj, new MouseOutContextMenuItemHandler());
	}
});

EventPropertiesContextMenu = InterfaceImplementor.extend({
	implement: function(obj)	{
		this.bind(obj, new ClickPropertiesContextMenuHandler());
		this.bind(obj, new MouseOverContextMenuItemHandler());
		this.bind(obj, new MouseOutContextMenuItemHandler());
	}
});

MouseOverContextMenuItemHandler = Handler.extend({
	getEventName: function()	{
		return "mouseover";
	},
	
	onEvent: function (e,obj)	{
		obj.setStyle('background-color','#888');
		obj.setStyle('color','#fff');
	}
});

MouseOutContextMenuItemHandler = Handler.extend({
	getEventName: function()	{
		return "mouseout";
	},
	
	onEvent: function (e,obj)	{
		obj.setStyle('background-color','#fff');
		obj.setStyle('color','#000');
	}
});

ClickPropertiesContextMenuHandler = Handler.extend({
	getEventName: function()	{
		return "click";
	},
	
	onEvent: function (e,obj)	{
		var str = "<div style='padding-left:50px; text-align:left'>";
		var controls = new Array();
		var btnOK = new Button("OK");
		var btnApply = new Button("Apply");
		var font = obj.getOriginObject().getTextArea().getFont();
		controls.push(btnApply);
		controls.push(btnOK);
		str += "Top:"+obj.getOriginObject().getPosition().top+"px ; Left:"+obj.getOriginObject().getPosition().left+"px<br/>";
		str += "Width:"+obj.getOriginObject().access().width()+"px ; Height:"+obj.getOriginObject().access().height()+"px<br/>";
		str += "Font-size: <input type='text' id='properties-font-size' value='"+font.getFontSize()+"' /><br/>";
		str += "Bold, Italic, etc<br/>";
		str += "Font-family: <input type='text' id='properties-font-family' value='"+font.getFontFamily()+"' /><br/>";
		str += "Color: <input type='text' id='properties-font-color' value='"+font.getColor()+"' /><br/>";
		str += "</div>";
		dialogId = dialog("Properties",str,controls);
		btnApply.implement(new ClickPropertiesButtonApply(obj.getOriginObject()));
		btnOK.implement(new ClickPropertiesButtonOK(dialogId,obj.getOriginObject()));
	}
});

ClickPropertiesButtonApply = InterfaceImplementor.extend({
	init: function(obj)	{
		this._super();
		this.obj = obj;
	},
	
	implement: function(obj)	{
		this.bind(obj, new ClickPropertiesButtonApplyHandler(this.obj));
	}
});

ClickPropertiesButtonApplyHandler = Handler.extend({
	init: function(obj){
		this.obj = obj;
	},
	
	getEventName: function(){
		return "click";
	},
	
	onEvent: function(e,o)	{
		var font = this.obj.getTextArea().getFont();
		font.setFontSize($("#properties-font-size").val());
		font.setFontFamily($("#properties-font-family").val());
		font.setColor($("#properties-font-color").val());
		this.obj.getTextArea().setFont(font);
		this.obj.getTextArea().updateText();
	}
});

ClickPropertiesButtonOK = InterfaceImplementor.extend({
	init: function(dialogId,obj)	{
		this._super();
		this.obj = obj;
		this.id = dialogId;
	},
	
	implement: function(obj)	{
		this.bind(obj, new ClickPropertiesButtonOKHandler(this.id,this.obj));
	}
});

ClickPropertiesButtonOKHandler = Handler.extend({
	init: function(id,obj){
		this.obj = obj;
		this.id = id;
	},
	
	getEventName: function(){
		return "click";
	},
	
	onEvent: function(e,o)	{
		var font = this.obj.getTextArea().getFont();
		font.setFontSize($("#properties-font-size").val());
		font.setFontFamily($("#properties-font-family").val());
		font.setColor($("#properties-font-color").val());
		this.obj.getTextArea().setFont(font);
		this.obj.getTextArea().updateText();
		$("#dialog_div_"+this.id).remove();
	}
});

SaveDiagram = InterfaceImplementor.extend({
	implement: function(obj)	{
		this.bind(obj, new ClickSaveDiagramHandler());
	}
});

ClickSaveDiagramHandler = Handler.extend({
	getEventName: function()	{
		return "click";
	},
	
	onEvent: function (e,obj)	{
		var objs = app.getObjectManager().getMainObjects();			
		var str = "";
		var o;
		var controls = new Array();
		var btnSave = new Button("Save");
		var btnCancel = new Button("Cancel");
		var dialogId;
		var dname;
		var objsToSave = new Array();
		for(var i=0;i<objs.length;i++){
			o = objs[i];
			var objToSave = objs[i].serialize();
			objsToSave.push(objToSave);
		}
		str += "Diagram Name: <input type='text' id='diagramname' value='default' />";
		controls.push(btnSave);
		controls.push(btnCancel);
		dialogId = dialog("Object detail",str,controls);
		dname = $("#diagramname");
		btnCancel.implement(new CloseDialog(dialogId));
		btnSave.implement(new SaveFile(dialogId,dname,objsToSave));
	}
});

SaveFile = InterfaceImplementor.extend({
	init: function(dialogId,dname,objsToSave){
		this._super();
		this.id = dialogId;
		this.dname = dname;
		this.objsToSave = objsToSave;
	},
	
	implement: function(obj){
		this.bind(obj, new ClickSaveFileHandler(this.id,this.dname,this.objsToSave));
	}
});

ClickSaveFileHandler = Handler.extend({
	init: function(id,dname,objsToSave){
		this.id = id;
		this.dname = dname;
		this.objsToSave = objsToSave;
	},
	
	getEventName: function(){
		return "click";
	},

	onEvent: function(e,obj){
		var name = this.dname.val();
		var json = {};
		var url = 'services/save.php';
		json.name = name;
		json.diagram = $.toJSON(this.objsToSave);
		$.ajax({
			cache: false,
			type:'POST',
			url: url,
			data: json,
			beforeSend: function(){
				alertMsg("alert","<img src='images/wait.gif'/>");
			},
			complete: function (data){
				alertMsg("alert",name +" is saved");
			}
		});
		
		$("#dialog_div_"+this.id).remove();
	}
	
});

LoadDiagram = InterfaceImplementor.extend({
	implement: function(obj)	{
		this.bind(obj, new ClickLoadDiagramHandler());
	}
});

ClickLoadDiagramHandler = Handler.extend({
	getEventName: function()	{
		return "click";
	},
	
	onEvent: function (e,obj)	{
		var str = "";
		var btnLoad = new Button("Load");
		var controls = new Array();
		var dname = "";
		var url = "services/listDiagrams.php";
		$.ajax({
			cache: false,
			type:'GET',
			url: url,
			beforeSend: function(){
				$("#dialogload-dlist").html("<img src='images/wait.gif'/>");
			},
			complete: function (data){
				var diagrams = $.parseJSON(data.responseText);
				var str = "";
				for(var i=0;i<diagrams.length;i++)	{
					var diagram = diagrams[i];
					str += diagram.name+",";
				}
				$("#dialogload-dlist").html(str);
			}
		});		
		str = "<div id='dialogload-dlist'></div>Diagram Name: <input id='diagramname' name='diagramname' type='text'/>";
		controls.push(btnLoad);
		dialogId = dialog("Choose file",str,controls);
		dname = $("#diagramname"); 
		btnLoad.implement(new ExtractDiagram(dialogId,dname));
	}
});

ExtractDiagram = InterfaceImplementor.extend({
	init: function(id,diagram)	{
		this._super();
		this.id = id;
		this.diagram = diagram;
	},
	
	implement: function(obj)	{
		this.bind(obj, new ExtractDiagramHandler(this.id, this.diagram));
	}
});

ExtractDiagramHandler = Handler.extend({
	init: function(id,diagram){
		this._super();
		this.id = id;
		this.diagram = diagram;
	},
	
	getEventName: function(){
		return "click";
	},
	
	onEvent: function(e,obj) {
		var diagramname = this.diagram.val(); 
		$("#dialog_div_"+this.id).remove();
		var objs = app.getObjectManager().getMainObjects();
		var url = 'services/load.php';
		url += '?name='+diagramname;
		while(objs.length > 0){
			objs[0].dispose();			
		}
		$.ajax({
			cache: false,
			type:'GET',
			url: url,
			beforeSend: function(){
				alertMsg("alert","<img src='images/wait.gif'/>");
			},
			complete: function (data){
				var strToLoad = data.responseText;
				var objsToLoad = $.parseJSON(strToLoad);
				var deserializer = new Deserializer();
				for(var i=0;i<objsToLoad.length;i++)	{
					var obj = objsToLoad[i];
					var deserializedObj = deserializer.deserialize(obj);
					app.getMainArea().addObject(deserializedObj);
					deserializedObj.afterLoad();
				}				
				alertMsg("alert","Completed !");
			}
		});
	}
});

CloseDialog = InterfaceImplementor.extend({
	init: function(id)	{
		this._super();
		this.id = id;
	},
	
	implement: function(obj)	{
		this.bind(obj, new CloseDialogHandler(this.id));
	}
});

CloseDialogHandler = Handler.extend({
	init: function(id)	{
		this._super();
		this.id = id;
	},

	getEventName: function ()	{
		return "click";
	},
	
	onEvent: function (e,obj)	{
		$("#dialog_div_"+this.id).remove();
	}
});

ClickToggleButton = InterfaceImplementor.extend({
	implement: function(obj)	{
		this.bind(obj, new ClickToggleButtonHandler());
	}
});

ClickToggleButtonHandler = Handler.extend({
	getEventName: function()	{
		return "click";
	},
	
	onEvent: function(e,obj)	{
		obj.access().toggleClass("toggledown");
		if(obj.access().hasClass("toggledown")){
			obj.state = true;
		}else{
			obj.state = false;
		}
	}
});

TestToggle = InterfaceImplementor.extend({
	implement: function(obj)	{
		this.bind(obj, new ClickTestToggleHandler());
	}
});

ClickTestToggleHandler = Handler.extend({
	getEventName: function()	{
		return "click";
	},
	
	onEvent: function(e,obj)	{
		dialog("alert","fine: "+obj.state,null);
	}
});
EventBinder = Class.extend	({
	fireEvent: function(jObject, event)	{
		jObject.trigger(event);
	},

	bindEvent: function(jObject, handlers)	{
		jObject.access().bind(handlers.getEventName(), function(e)	{
			handlers.onEvent(e, jObject);
		});
	}
});
/**
 * Observer interface. 
 * Used for formalizing the observer design pattern,
 * especially in an event-based application
 * Provide the following methods:
 *  - notify(eventName, eventData): called when an arbitrary event is triggered
 *  - registerObserver(): register the current object to be an observer
 *  - unregisterObserver(): unregister the current object, and it's no longer an observer
 *  @augments InterfaceImplementor
 *  @author griever
 */
ObserverInterface = InterfaceImplementor.extend({
	
	implement: function(obj)	{
		obj.prototype.notify = obj.prototype.notify || function(eventName, eventData)	{
			var methodName = "on"+eventName;
			if (typeof this[methodName] != 'undefined')	{
				var method = this[methodName];
				method.call(this, eventData);
				return true;
			}
			return false;
		};
		
		obj.prototype.registerObserver = obj.prototype.registerObserver || function()	{
			var subject = SingletonFactory.getInstance(Subject);
			subject.attachObserver(this);
		};
		
		obj.prototype.unregisterObserver = obj.prototype.unregisterObserver || function()	{
			var subject = SingletonFactory.getInstance(Subject);
			subject.detachObserver(this);
		};
	}
});

/**
 * Event Subject (mediator or notifier)
 * @augments Class
 * @author griever
 */
Subject = Class.extend({
	
	/**
	 * Initialize fields
	 * @constructor
	 */
	init: function()	{
		this.observers = Array();
	},
	
	/**
	 * Attach an observer
	 * @function
	 * @param {observer} the observer
	 */
	attachObserver: function(observer)	{
		this.observers.push(observer);
	},
	
	/**
	 * Detach an observer
	 * @function
	 * @param {observer} the observer
	 */
	detachObserver: function(observer)	{
		if (observer == undefined)
			return;
		var index = this.observers.indexOf(observer);
		if (index > 0)	{
			this.observers.splice(index, 1);
		}
	},
	
	/**
	 * Notify an event to all observers
	 * @function
	 * @param {eventName} the name of the event which should contains characters only
	 * @param {eventData} the data associated with the event
	 */
	notifyEvent: function(eventName, eventData)	{
		var count = 0;
		for(var i=0;i<this.observers.length;i++)	{
			try {
				var result = this.observers[i].notify(eventName, eventData);
				if (result == true)	{
					count++;
				}
			} catch (err)	{
				log(err);
			}
		}
	}
});
/**
 * PluginManager. Manages all registered plugins
 * @augments Class
 * @author griever
 */
PluginManager = Class.extend({
	
	/**
	 * Initialize fields
	 * @constructor
	 */
	init: function()	{
		if(PluginManager.singleton == undefined){
			throw "Singleton class, can not be directly created !";
			return undefined;
		}
		var subject = SingletonFactory.getInstance(Subject);
		subject.attachObserver(this);
		this.plugins = Array();
	},
	
	/**
	 * Add plugin to the manager
	 * @function
	 * @param {plugin} the plugin to be added
	 * @param {delay} whether the plugin should be loaded after added
	 */
	addPlugin: function(plugin, delay)	{
		var pluginMeta = {};
		if (delay != true)
			plugin.onLoad();
		this.plugins.push(plugin);
	},
	
	/**
	 * Remove plugin at the specified index
	 * @function
	 * @param {index} the index of the plugin to be removed
	 */
	removePlugin: function(index)	{
		var plugin = this.plugins[index];
		if (plugin != undefined)	{
			plugin.onUnload();
			this.plugins.splice(index, 1);
		}
	},
	
	/**
	 * Get all plugins
	 * @function
	 * @returns {Array} the current plugins
	 */
	getPlugins: function()	{
		return this.plugins;
	},
	
	/**
	 * Remove every plugins managed by this manager
	 * @function
	 */
	removeAllPlugins: function()	{
		for(var i=0;i<this.plugins.length;i++)	{
			var plugin = this.plugins[i];
			if (plugin.isLoaded())	{
				plugin.onUnload();
			}
		}
		this.plugins = Array();
	},
	
	/**
	 * Event hook. Triggered by the Subject and in turn triggers all plugins that it manages
	 * @function
	 * @param {eventName} the event name
	 * @param {eventData} the event data
	 */
	notify: function(eventName, eventData)	{
		for(var i=0;i<this.plugins.length;i++)	{
			var plugin = this.plugins[i];
			if (plugin.isLoaded())	{
				var methodName = "on"+eventName;
				if (typeof plugin[methodName] != 'undefined')	{
					var method = plugin[methodName];
					method.call(plugin, eventData);
				}
			}
		}
	}
}).implement(ObserverInterface);

/**
 * The plugin interface.
 * Provide the following methods:
 *  - isLoaded(): check if the plugin is loaded
 *  - getName(): get the plugin's name
 *  - onLoad(): called when the plugin is loaded
 *  - onBegin(): called when the plugin begins its routine
 *  - onEnd(): called when the plugin ends its routine
 *  - onUnload(): called when the plugin is unloaded from memory
 * @augments InterfaceImplementor
 * @author griever
 */
PluginInterface = InterfaceImplementor.extend({
	implement: function(obj)	{

		obj.prototype.isLoaded = obj.prototype.isLoaded || function()	{
			if (this.loaded == undefined)
				this.loaded = false;
			return this.loaded;
		};
		
		obj.prototype.getName = obj.prototype.getName || function()	{
			return this.name;
		};
		
		obj.prototype.onLoad = obj.prototype.onLoad || function()	{
			this.loaded = true;
			this.onBegin();
		};
		
		obj.prototype.onBegin = obj.prototype.onBegin || function() {};
		
		obj.prototype.onEnd = obj.prototype.onEnd || function() {};
		
		obj.prototype.onUnload = obj.prototype.onUnload || function()	{
			this.loaded = false;
			this.onEnd();
		};
		
		//super interfaces
		new ObserverInterface().implement(obj);
	}
});

/**
 * Interval timer interface. Used for circular portlets or plugins
 * Provide the following methods:
 *  - startInterval(interval, callback): start the interval timer
 *  - stopInterval(): stop the interval timer
 *  @augments InterfaceImplementor
 *  @author griever
 */
IntervalTimerInterface = InterfaceImplementor.extend({
	implement: function(obj)	{
		obj.prototype.startInterval = obj.prototype.startInterval || function(interval, callback)	{
			//stop previous interval timer if any
			if (this.intervalSetup == true)	{
				this.stopInterval();
			}
			this.intervalSetup = true;
			var _this = this;
			this.currentIntervalID = setInterval(function() {callback.call(_this);}, interval);
		};
		
		obj.prototype.stopInterval = obj.prototype.stopInterval || function()	{
			if (this.currentIntervalID != undefined)
				clearInterval(this.currentIntervalID);
			else	{
				//console.warn('bug! currentIntervalID not defined');
			}
		};
	}
});
/**
 * Page is a class for attaching portlets to appropriate position
 * a Page manages the display 
 * FIXME: not sure about provide supporting for template in each page ! 
 * currently unsupport
 * @augments Class
 * @author griever
 */

Page = Class.extend({
	
	/**
	 * Initialize fields
	 * @constructor
	 */
	init: function(){
		if(Page.singleton == undefined){
			throw "Page is Singleton !";
			return undefined;
		}
		this.portletContainer = SingletonFactory.getInstance(PortletContainer);
		this.pluginManager = SingletonFactory.getInstance(PluginManager);
		this.pagename = "";
		this.subject = SingletonFactory.getInstance(Subject);
	},
	
	/**
	 * Attach portlets to the page
	 * @function
	 */
	attachPortlets: function(){
		/*
		 * check for consistency with layout in here
		 * + portlet existence
		 * + portlet position
		 * + portlet active (?)
		 */
		for( var item in this.layout ){
			item = this.layout[item];
			if(item.active == undefined){
				item.active = true;
			}
			if (item.params == undefined)	{
				item.params = Array();
			}
			var existed = false;
			for( var i=0; i<this.portletContainer.portlets.length; i++ )	{
				var portletMeta = this.portletContainer.portlets[i];
				if( item.portlet === portletMeta.portlet.getName() ){
					existed = true;
					portletMeta.portlet.setInitParameters(item.params);
					portletMeta.active = item.active;
					if( item.position !== portletMeta.position ){
						portletMeta.position = item.position;
						this.portletContainer.movePortlet(portletMeta,item.position);
					}
					if ( item.active == true)	{
						//portlet need reload?
						try {
							portletMeta.portlet.onReloadPage();
							portletMeta.loaded = true;
						} catch (err)	{
							log(err);
						}
					}
					break;
				}
			}
			if(!existed){
				if (window[item.portlet] == undefined)	{
					log('portlet '+item.portlet+' is undefined');
				} else {
					var portlet = new window[item.portlet]();
					portlet.setInitParameters(item.params);
					this.portletContainer.addPortlet(portlet,item);
				}
			}
		}
		var portletsToRemoved = Array();
		for( var i=0; i<this.portletContainer.portlets.length; i++ )	{
			var portletMeta = this.portletContainer.portlets[i];
			var keep = false;
			for(var item in this.layout){
				item = this.layout[item];
				if( item.portlet === portletMeta.portlet.getName() ){
					if (item.active == false)	{
						this.portletContainer.deactivatePortlet(portletMeta);
					}
					keep = true;
					break;
				}
			}
			if(!keep){
				portletsToRemoved.push(portletMeta);
			}
		}
		for(var i=0;i<portletsToRemoved.length;i++)	{
			var plt = portletsToRemoved[i];
			var indexOf = this.portletContainer.portlets.indexOf(plt);
			this.portletContainer.removePortlet(indexOf);
		}
	},
	
	/**
	 * Private function
	 * Parse the layout
	 * @function
	 */
	generateData: function(pagename){
		var data = {};
		var tmp = {};

		if (pagename == undefined)	{
			throw {"Exception": "NotFound", "Message": "Page name is undefined"};
			return undefined;
		}
		var app = SingletonFactory.getInstance(Application);
		var jsonObj = app.getResourceManager().requestForResource("portlets",pagename);
		if (jsonObj == undefined)	{
			//console.error(pagename+' not exist!');
			throw {"Exception": "NotFound", "Message": 'Page name "'+pagename+'" not found!'};
			return undefined;
		}
		var jsonText = jsonObj.html();
		tmp = eval("("+jsonText+")");
		data.parent = tmp.parent;
		data.plugins = tmp.plugins;
		data.layout = tmp.portlets;
		var i,j;
		var toAddPlugins = new Array();
		var toAddPortlets = new Array();
		while(data.parent != undefined){
			jsonObj = app.getResourceManager().requestForResource("portlets",data.parent);
			if (jsonObj == undefined)	{
				//console.error(data.parent+' not exist!');
				throw {"Exception": "NotFound", "Message": '(Parent)Page name "'+data.parent+'" not found!'};
				return undefined;
			}
			jsonText = jsonObj.html();
			toAddPlugins = new Array();
			toAddPortlets = new Array();
			tmp = eval("("+jsonText+")");
			for( i=0; i<tmp.plugins.length; i++ )	{
				var existed = false;
				for( j=0; j<data.plugins.length; j++ )	{
					if(tmp.plugins[i].plugin == data.plugins[j].plugin){
						existed = true;
						break;
					}
				}
				if(!existed){
					toAddPlugins.push(tmp.plugins[i]);
				}
			}
			for( i=0; i<tmp.portlets.length; i++ )	{
				var existed = false;
				for( j=0; j<data.layout.length; j++ )	{
					if(tmp.portlets[i].portlet == data.layout[j].portlet){
						existed = true;
						break;
					}
				}
				if(!existed){
					toAddPortlets.push(tmp.portlets[i]);
				}
			}
			for( i=0;i<toAddPlugins.length;i++ ){
				data.plugins.push(toAddPlugins[i]);
			}
			for( i=0;i<toAddPortlets.length;i++ ){
				data.layout.push(toAddPortlets[i]);
			}
			data.parent = tmp.parent;
		}
		/*
		if(tmp.position != undefined){
			data.template = app.getResourceManager().requestForResource("page",pagename).html();
			data.position = tmp.position;
		}
		*/
		return data;
	},
	
	/**
	 * Get the current request
	 * @function
	 * @returns {Request} the current request
	 */
	getRequest: function(){
		return this.request;
	},
	
	/**
	 * Change the current request
	 * This method <b>should not</b> be called by developers
	 * @function
	 * @param {Request} the new request
	 */
	setRequest: function(request){
		this.request = request;
	},
	
	/**
	 * Attach plugins to the page
	 * @function
	 */
	attachPlugins: function(){
		var oldPlugins = this.pluginManager.getPlugins();
		for(var i in oldPlugins)	{
			var oldPlg = oldPlugins[i];
//			//console.log('old plugin: '+oldPlg.getName());
			oldPlg.keep = false;
		}
		
		for (var j in this.plugins)	{
			var newPlg = this.plugins[j];
			//check if the plugin exists
			var existed = false;
			for(var i=0; i<oldPlugins.length; i++)	{
				existed = false;
				var oldPlg = oldPlugins[i];
//				//console.log('check plugin '+newPlg.plugin+' against '+oldPlg.getName());
				if (oldPlg.getName() == newPlg.plugin)	{
					//console.log('plugin '+newPlg.plugin+' existed!');
					oldPlg.keep = true;
					existed = true;
					break;
				}
			}
			if (!existed)	{
				//console.log("load plugin: "+newPlg.plugin);
				if(window[newPlg.plugin] == undefined){
					//console.warn('Plugin '+newPlg.plugin+' is undefined!');
				} else {
					var plugin = new window[newPlg.plugin];
					plugin.keep = true;
					this.pluginManager.addPlugin(plugin, eval(newPlg.delay));
				}
			}
		}
		
		//find plugins that need to be removed
		var pluginsToRemoved = Array();
		for(var i in oldPlugins){
			var oldPlg = oldPlugins[i];
			if (oldPlg.keep != true)	{
				//console.log('plugin removed: '+oldPlg.getName());
				pluginsToRemoved.push(oldPlg);
			}
		}
		
		//removed unused plugins
		for(var i=0;i<pluginsToRemoved.length;i++)	{
			var plg = pluginsToRemoved[i];
			var indexOf = this.pluginManager.getPlugins().indexOf(plg);
			this.pluginManager.removePlugin(indexOf);
		}
		
		var subject = SingletonFactory.getInstance(Subject);
		subject.notifyEvent('ReloadPlugin');
//		//console.log('newplugin', this.pluginManager.getPlugins());
	},
/*
	attachTemplate: function(){
		if(this.position != undefined){
				//console.log("attachTemplate");
				this.temp = new Array();
				for(var i in $("#"+this.position).children()){
					if(!isNaN(i)){
						var obj = $($("#"+this.position).children()[i]);
						obj.detach();
						this.temp.push(obj);
					}
				}
				//console.log("position:"+this.position);
				$("#"+this.position).html(this.template);
		}
	},
	
	wrapUpDisplay: function(){
		if(this.position != undefined){
			var tmp = new Array();
			for(var i in $("#"+this.position).children()){
				if(!isNaN(i)){
					var obj = $($("#"+this.position).children()[i]);
					obj.detach();
					tmp.push(obj);
				}
			}
			
			$("#"+this.position).html(tmp);
		}
	},
*/
	
	/**
	 * Called when the page begins its routine
	 * Parse the layout and attach plugins
	 * @param {pagename} the page name
	 * @function
	 */
	onBegin: function(pagename)	{
		var data = this.generateData(pagename);
		if (data == undefined)
			return;
		this.pagename = pagename;
		this.layout = data.layout;
		this.plugins = data.plugins;
		this.attachPlugins();
		this.subject.notifyEvent("PageBegan");
		/*
		this.template = data.template;
		this.position = data.position;
		*/
	},
	
	/**
	 * Run the page, attach portlets
	 */
	run: function()	{
		/*
		this.attachTemplate();
		*/
		this.attachPortlets();		
		this.subject.notifyEvent("AllPorletAdded");
		this.portletContainer.loadPortlets();
		this.subject.notifyEvent("AllPorletLoaded");
		/*
		this.wrapUpDisplay();
		*/
	},
	
	onEnd: function()	{
		
	},
	
	dispose: function()	{
		
	}
});
PortletCanvas = Canvas.extend({
	init: function(portletName)	{
		this._super();
		this.addClass('portlet');
		this.addClass('portlet-canvas');
	}
});

/**
 * An interface for all portlets
 * Exposed method:
 * 	- void onBegin()
 *  - void run()
 *  - void onEnd()
 *  - String getName()
 *  - void setPortletPlaceholder(PortletPlaceholder)
 *  - PortletPlaceholder getPortletPlaceholder()
 *  - getPage(): get the current page
 *  - getRequest(): get the current request
 *  - requestForResource(): get the resource in the prepared portlet-data
 *  - requestForEffectiveResource(): get the resource in the portlet's DOM
 *  - getLocalizedText(): get the localized text by ID
 *  - getLocalizedMessage(): get the message by ID
 *  @augments InterfaceImplementor
 *  @author griever
 */
PortletInterface = InterfaceImplementor.extend({
	implement: function(obj)	{
		obj.prototype.getName = obj.prototype.getName || function()	{
			return this.name;
		};
		obj.prototype.onBegin = obj.prototype.onBegin || function(){};
		obj.prototype.run = obj.prototype.run || function(){};
		obj.prototype.onEnd = obj.prototype.onEnd || function(){};
		obj.prototype.setPortletPlaceholder = obj.prototype.setPortletPlaceholder || function(plhd)	{
			this.placeholder = plhd;
		};
		
		obj.prototype.getPage = obj.prototype.getPage || function()	{
			return SingletonFactory.getInstance(Page);
		};
		
		obj.prototype.getInitParameters = obj.prototype.getInitParameters || function()	{
			if (this.initParams == undefined)
				this.initParams = Array();
			return this.initParams;
		};
		
		obj.prototype.setInitParameters = obj.prototype.setInitParameters || function(params)	{
			this.initParams = params;
		};
		
		obj.prototype.getRequest = obj.prototype.getRequest || function()	{
			return this.getPage().getRequest();
		};
		
		obj.prototype.requestForMatchingEffectiveResource = obj.prototype.requestForMatchingEffectiveResource || function(resourceName, condition)	{
			var app = SingletonFactory.getInstance(Application);
			var rm = app.getResourceManager();
			return rm.requestForCustomResource("#effective-area #"+this.name+"-"+resourceName+" "+condition);
		};
		
		obj.prototype.requestForResource = obj.prototype.requestForResource || function(resourceName)	{
			var app = SingletonFactory.getInstance(Application);
			var rm = app.getResourceManager();
			return rm.requestForCustomResource("#"+this.name+"-RootData #"+this.name+"-"+resourceName);
		};
		
		obj.prototype.requestForEffectiveResource = obj.prototype.requestForEffectiveResource || function(resourceName)	{
			var app = SingletonFactory.getInstance(Application);
			var rm = app.getResourceManager();
			return rm.requestForCustomResource("#effective-area #"+this.name+"-"+resourceName);
		};
		
		obj.prototype.onReloadPage = obj.prototype.onReloadPage || function()	{};
		
		obj.prototype.getResourceID = obj.prototype.getResourceID || function(resourceName)	{
			return this.name+"-"+resourceName;
		};
		
		obj.prototype.getLocalizedText = obj.prototype.getLocalizedText || function(resourceName)	{
			var app = SingletonFactory.getInstance(Application);
			var rm = app.getResourceManager();
			var res = rm.requestForResource(this.name, "Text"+resourceName);
			if (res == undefined)
				return undefined;
			return res.html();
		};
		
		obj.prototype.getLocalizedMessage = obj.prototype.getLocalizedMessage || function(resourceName)	{
			var app = SingletonFactory.getInstance(Application);
			var rm = app.getResourceManager();
			var res = rm.requestForResource(this.name, "Message"+resourceName);
			if (res == undefined)
				return undefined;
			var unresolved = res.html();
			
			var resolved = unresolved;
			//resolved string pattern
			for(var i=1;i<arguments.length;i++)	{
				resolved = resolved.replace("%"+i, arguments[i]);
			}
			return resolved;
		};
		
		obj.prototype.getPortletPlaceholder = obj.prototype.getPortletPlaceholder || function()	{
			return this.placeholder;
		};
	}
});

/**
 * An interface for all portlets which need rendering
 * Exposed method:
 * 	- Object model
 * 	- String viewId
 *  - void render()
 */
RenderInterface = InterfaceImplementor.extend({
	implement: function(obj)	{
		obj.prototype.render = obj.prototype.render || function(){
			this.viewId = this.viewId || this.getName()+"View";
			this.model = this.model || {};
//			if(this.viewId == undefined || this.model == undefined){
//				throw "No viewId or model for rendering";
//			}
			return tmpl(this.viewId, this.model);
		};
		
		obj.prototype.renderView = obj.prototype.renderView || function(view, model)	{
			return tmpl(this.name+"-"+view, model);
		};
	}
});

/**
 * A placeholder to store a single portlet
 * It acts as a bridge between Portlet and PortletCanvas
 * @augments Class
 * @author griever
 */
PortletPlaceholder = Class.extend({
	init: function(canvas)	{
		this.canvas = canvas;
	},
	
	/**
	 * Add an object to canvas
	 * @function
	 * @param {object} the object to add
	 */
	addToCanvas: function(object)	{
		//console.log('add '+object.toHtml()+' into '+this.canvas.id);
		this.canvas.addObject(object);
	},
	
	/**
	 * Clear everything and repaint the canvas
	 * @param {html} the HTML data to be painted
	 * @function
	 */
	paintCanvas: function(html)	{
		this.canvas.access().html(html);
		var subject = SingletonFactory.getInstance(Subject);
		subject.notifyEvent('HtmlUpdated');
	},
	
	/**
	 * Append to the canvas
	 * @param {html} the HTML data to be appended
	 * @function
	 */
	drawToCanvas: function(html)	{
		this.canvas.access().append(html);
		var subject = SingletonFactory.getInstance(Subject);
		subject.notifyEvent('HtmlUpdated');
	},
	
	/**
	 * Access the underlying canvas
	 * @returns {PortletCanvas} the canvas
	 */
	getCanvas: function()	{
		return this.canvas;
	}
});

/**
 * A container which 'runs' multiple portlets
 */
PortletContainer = Class.extend({
	init: function()	{
		if(PortletContainer.singleton == undefined){
			throw "Singleton class";
			return undefined;
		}
		this.portlets = Array();
	},
	
	/**
	 * Add a portlet to this container and initialize it
	 * @function
	 * @param {portlet} the portlet to be added
	 * @param {position} the position of the portlet
	 * @param {active} whether the portlet should be loaded
	 */
	addPortlet: function(portlet, item)	{
//		console.log('adding portlet: '+portlet.getName(), 'color: red');
		var portletMeta = {};
		for(var i in item)	{
			portletMeta[i] = item[i];
		}
		portletMeta.portlet = portlet;
		if (portletMeta.order == undefined)
			portletMeta.order = '';
		portletMeta.loaded = false;
		this.portlets.push(portletMeta);
		try 
		{
			portlet.onBegin();
		} 
		catch (err)	{
			log(err);
		}
	},
	
	/**
	 * Move the portlet to another position
	 * @function
	 * @param {portlet} the portlet to be moved
	 * @param {newPosition} the new position
	 */
	movePortlet: function(portletMeta, newPosition)	{
		var portletPosition = new PrebuiltCanvas(newPosition);
		var portletCanvas = new PrebuiltCanvas(portletMeta.portlet.getPortletPlaceholder().getCanvas().id);
		this.attachPortletHtml(portletPosition, portletCanvas, portletMeta);
	},
	
	/**
	 * Load all active portlets, execute them synchronously
	 * @function
	 */
	loadPortlets: function()	{
		for(var i=0;i<this.portlets.length;i++)	{
			var portletMeta = this.portlets[i];
			if (portletMeta.active == true && !portletMeta.loaded)	{
				this.activatePortlet(portletMeta);
				portletMeta.loaded = true;
			}
		}
	},
	
	/**
	 * Get all portlets
	 * @function
	 * @returns {Array} All loaded portlets
	 */
	getPortlets: function()	{
		return this.portlets;
	},
	
	/**
	 * Get portlet meta using the portlet's name
	 * @function
	 * @param {name} the portlet's name
	 */
	getPortletMetaByName: function(name)	{
		var i;
		for( i=0; i<this.portlets.length; i++ ){
			if(this.portlets[i].portlet.getName() == name){
				return this.portlets[i];
			}
		}
	},
	
	/**
	 * Remove portlet at the specified position
	 * @function
	 * @param {position} the position of the portlet to be removed
	 */
	removePortlet: function(position)	{
		var portletMeta = this.portlets[position];
		if (portletMeta != undefined)	{
			this.portlets.splice(position,1);
			portletMeta.portlet.onEnd();
			if (portletMeta.portlet.getPortletPlaceholder())	{
				//console.log("dispose canvas of portlet: "+portletMeta.portlet.getName());
				portletMeta.portlet.getPortletPlaceholder().getCanvas().dispose();
			}
		}
	},
	
	attachPortletHtml: function(portletPosition, portletCanvas, portletMeta)	{
		var jPortletCanvas = portletPosition.access();
		var canvases = jPortletCanvas.find('.portlet.portlet-canvas');

		var found = false;
		for(var i=0;i<canvases.length;i++)	{
			var canvasI = canvases[i];
			if ($(canvasI).attr('order') > portletMeta.order)	{
				portletPosition.addObjectBeforePosition(portletCanvas, canvasI);
				found = true;
				break;
			}
		}
		if (found == false)	{
			portletPosition.addObject(portletCanvas);
		}
		portletCanvas.access().attr('order', portletMeta.order);
	},
	
	/**
	 * Activate a portlet
	 * @function
	 * @param {portletMeta} the metadata of the portlet to be activated
	 */
	activatePortlet: function(portletMeta)	{
		var portlet = portletMeta.portlet;
		if (portletMeta.loaded)	{
			return;
		}
		var portletPosition = new PrebuiltCanvas(portletMeta.position);
		var portletCanvas = new PortletCanvas(portlet.name);
		this.attachPortletHtml(portletPosition, portletCanvas, portletMeta);
		portletCanvas.setAttribute('portlet', portlet.name);
		var portletPlaceholder = new PortletPlaceholder(portletCanvas);
		portlet.setPortletPlaceholder(portletPlaceholder);
		portletMeta.loaded = true;
		try
		{
			portlet.run();
		} 
		catch (err)	{
			log(err);
		}
	},
	
	/**
	 * Deactivate a portlet
	 * @function
	 * @param {portletMeta} the metadata of the portlet to be deactivated
	 */
	deactivatePortlet: function(portletMeta)	{
		var portlet = portletMeta.portlet;
		if (!portletMeta.loaded)	{
			return;
		}
		portletMeta.loaded = false;
		if (portlet.getPortletPlaceholder())	{
			portlet.getPortletPlaceholder().paintCanvas('');
		}
	}
});
DefaultErrorHandler = Class.extend({
	handle: function(err, event) {
		if (typeof err == 'object') {
			if (err.Exception == 'RequestInterrupted') {
				return;
			}
			if (err.Exception != undefined)	{
				alert("["+err.Exception+"Exception] "+err.Message);
			} else {
				alert(err);
			}
			return;
		}
		alert("Error caught: "+err);
	}
});

/**
 * Represents a request
 */
Request = Class.extend({
	init: function(name, type, params, hideParams) {
		if (name != undefined)
			name = name.trim();
		this.name = name;
		this.type = type;
		if (params == undefined) {
			params = Array();
		}
		if (hideParams == undefined) {
			hideParams = Array();
		}
		this.params = params;
		this.hiddenParams = hideParams;
		this.setParams(params);
		this.demanded = true;
	},
	/**
	 * Check if the request is demanded by the application itself
	 * @function
	 * @returns {bool} true or false
	 */
	isDemanded: function() {
		return this.demanded;
	},
	
	/**
	 * Change the demanding flag of the current request
	 * Demanded request will be automatically routed
	 * @function
	 * @param {b} the demanding flag
	 */
	demand: function(b) {
		this.demanded = b;
	},
	setParam: function(key, value) {
		this.params[key] = value;
	},
	setParams: function(params) {
		this.params = params;
	},
	getParam: function(key, defaultValue) {
		if (this.params[key] == undefined) {
			return defaultValue;
		}
		return this.params[key];
	},
	getParams: function() {
		return this.params;
	},
	addHash: function(strToAdd) {
		window.location.hash = strToAdd;
	},
	setName: function(name) {
		this.name = name;
	},
	getName: function() {
		return this.name;
	},
	getType: function() {
		return this.type;
	}
});

Request.setProactive = function(b, url) {
	if (url == undefined)
		url = window.location.hash;
	//console.log('set proactive to '+b+' for url: '+url);
	//	//console.warn('called by '+Request.setProactive.caller);
	if (Request.proactive == undefined)
		Request.proactive = {};
	Request.proactive[url] = b;
};
Request.getProactive = function(url) {
	if (url == undefined)
		url = window.location.hash;
	if (Request.proactive == undefined)
		Request.proactive = {};
	return Request.proactive[url];
};
RequestHandler = Class.extend({
	
	/**
	 * Init fields
	 * @constructor
	 */
	init: function() {
		this.currentPage = undefined;
		this.requestInterrupted = false;
		this.autoRouteDefault = true;
		this.systemProperties = SingletonFactory.getInstance(Application).getSystemProperties();
		this.errorHandler = new DefaultErrorHandler();
	},
	
	/**
	 * Change the error handler
	 */
	setErrorHandler: function(errorHandler) {
		this.errorHandler = errorHandler;
	},
	
	/**
	 * Route (if needed) and handle a request
	 * @function
	 * @param {request} the request to be handled
	 */
	handleRequest: function(request) {
		//console.log('current page is '+this.currentPage);
		if (this.currentPage != undefined) {
			//console.log("Request Interrupted");
			this.requestInterrupted = true;
		} else {
			this.requestInterrupted = false;
		}
		this.routeRequest(request);
		this._handleRequest(request);
	},
	
	_handleRequest: function(request) {
		var name = request.getName();
		var page = SingletonFactory.getInstance(Page);
		this.currentPage = page;
		page.setRequest(request);
		//console.log('current page begin: '+request.getName());
		try 
		{
			page.onBegin(name);
		} 
		catch (err) {
			log(err);
			/*
			* display a message similar to 'this applet failed to load. click here to reload it'
			*/
			this.errorHandler.handle(err, 'onBegin');
		}

		//console.log('current page running: '+request.getName());

		try 
		{
			page.run();
		} 
		catch (err) {
			log(err);
			/*
 			* display a message box notify the error
 			*/
			this.errorHandler.handle(err, 'run');
		}

		try 
		{
			page.onEnd();
		} 
		catch (err) {
			log(err);
			this.errorHandler.handle(err, 'onEnd');
		}

		//console.log('current page finished: '+request.getName());
		this.currentPage = undefined;

		var subject = SingletonFactory.getInstance(Subject);
		subject.notifyEvent("HtmlRendered");
		//		//console.log(currentPage);
		if (this.requestInterrupted == true) {
			throw {"Exception":"RequestInterrupted"};
		}
	},
	
	/**
	 * Define setter and getter for the window location hash
	 */
	prepareForRequest: function() {
		if(!("hash" in window.location)) {
			window.location.__defineGetter__("hash", function() {
				if(location.href.indexOf("#") == -1)
					return "";
				return location.href.substring(location.href.indexOf("#"));
			});
			window.location.__defineSetter__("hash", function(v) {
				if(location.href.indexOf("#") == -1)
					location.href += v;
				location.href = location.substring(0,location.href.indexOf("#")) + v;
			});
		}
	},
	
	/**
	 * Create a request based on the current URL
	 * @function
	 */
	assembleRequest: function() {
		var defaultPage = SingletonFactory.getInstance(Application).getSystemProperties().get('page.default', 'Home');
		if(window.location.hash == "") {
			var request = new Request(defaultPage, null, null, {'page': ''});
			var subject = SingletonFactory.getInstance(Subject);
			return request;
		} else {
			//console.log("hey!");
			var hash = window.location.hash;
			hash = hash.substring(1,hash.length);
			if (hash.charAt(0) == '!')	{
				hash = hash.substring(1, hash.length);
			}
			var tmp = hash.split("/");
			var params = new Array();
			var pagename = "";
			var i = 0;

			while(i<tmp.length) {
				if(tmp[i] != "") {
					params[tmp[i]] = tmp[i+1];
					if(tmp[i] == "page") {
						pagename = params[tmp[i]];
					}
					i = i + 2;
				} else {
					i = i + 1;
				}
			}
			
			var request = new Request(pagename, null, params);
			request.demand(false);
			return request;
		}
	},
	
	/**
	 * Modify the URL (i.e the window location) based on the request
	 * @function
	 * @param {request} the request to be routed
	 */
	routeRequest: function(request) {
		//if this request neither proactive nor demanded, then there's no point routing it
		if (Request.getProactive() == false && request.isDemanded() == false)
			return;
		var oldHash = window.location.hash;
		var str = "!";
		if ( ( request.getName() == undefined || request.getName() == "" ) && this.autoRouteDefault ) {
			var pagename = this.systemProperties.get('page.default');
			//console.warn('page is undefined! Using default homepage ['+pagename+']');
			if (pagename == undefined) {
				//console.error('Default page is undefined! I give up for now!');
				throw {"Exception": "NotFound", "Message": "Both default page and parameter page is undefined"};
				return undefined;
			}
			request.setName(pagename);
			request.hiddenParams.page = '';
		}
		request.getParams()['page'] = request.getName();
		for(var key in request.getParams()) {
			if (request.hiddenParams.hasOwnProperty(key)) {
				continue;
			}
			if (typeof request.getParams()[key] == 'function' || typeof request.getParams()[key] == 'object')	{
				continue;
			}
			value = request.params[key];
			if (value != undefined)
				str += key+"/"+value+"/";
			else
				str += key+"/";
		}
		str = str.substring(0,str.length-1);
		if(!("hash" in window.location)) {
			window.location.__defineGetter__("hash", function() {
				if(location.href.indexOf("#") == -1)
					return "";
				return location.href.substring(location.href.indexOf("#"));
			});
			window.location.__defineSetter__("hash", function(v) {
				if(location.href.indexOf("#") == -1)
					location.href += v;
				location.href = location.substring(0,location.href.indexOf("#")) + v;
			});
		}
		//mark the current request as Proactive, so it won't trigger another history event
		Request.setProactive(true, '#!'+str);
		window.location.hash = str;
	}
});

/**
 * The bootstrap class.
 * The application's flow is defined here
 * Implement ObserverInterface
 * @augments Class
 */
Bootstrap = Class.extend({
	/**
	 * Called when the application start running
	 * Subclass can override this method to change the default flow
	 * @function
	 */
	run: function()	{
		this.registerObserver();
		this.setupRequestHandler();
		this.executeRequest();
	},

	/**
	 * Event-hooked function.
	 * @function
	 */
	onRequestRoute: function(eventData)	{
		this.requestHandler.handleRequest(eventData);
	},
	
	/**
	 * Event-hooked function.
	 * @function
	 */
	onNeedAssembleRequest: function(eventData)	{
		this.executeRequest();
	},

	/**
	 * Initialize the request handler
	 * @function
	 */
	setupRequestHandler: function()	{
		this.requestHandler = new RequestHandler();
	},
	
	/**
	 * Execute the current request
	 * @function
	 */
	executeRequest: function()	{
		this.requestHandler.prepareForRequest();
		var request = this.requestHandler.assembleRequest();
		if (request != undefined)	{
			var subject = SingletonFactory.getInstance(Subject);
			subject.notifyEvent('RequestRoute', request);
		}
	}
}).implement(ObserverInterface);
/**
 * 
 */

utils_items = {};

/**
 * Generate an unique ID
 * 
 * @param type
 *            String
 * @returns
 */
function generateId(type)	{
	if (!isPropertySet(utils_items, type))	{
		setProperty(utils_items, type, 0);
	}
	setProperty(utils_items, type, getProperty(utils_items, type)+1);
	return type+"-"+getProperty(utils_items, type);
}

function generateEvent(eventName, eventData){
    var subject = SingletonFactory.getInstance(Subject);
    subject.notifyEvent(eventName, eventData);
}

function setProperty(obj, prop, val)	{
	obj.prop = val;
}

function getProperty(obj, prop)	{
	return obj.prop;
}

function isPropertySet(obj, prop)	{
	if (typeof obj.prop != 'undefined')	{
		return true;
	}
	return false;
}


Array.max = function( array ){
    return Math.max.apply( Math, array );
};
Array.min = function( array ){
    return Math.min.apply( Math, array );
};

Array.nextBigger = function( array,val ){
	var result = Number.MAX_VALUE;
	for(var i=0; i < array.length; i++){
		if(array[i] > val && array[i] < result){
			result = array[i];
		}
	}
	return result;
};

Array.nextLess = function( array,val ){
	var result = Number.MIN_VALUE;
	for(var i=0; i < array.length; i++){
		if(array[i] < val && array[i] > result){
			result = array[i];
		}
	}
	return result;
};

function dialog ( title,msg,controls ){
	var id = Math.floor(Math.random()*101);
	var dialog_div = document.createElement("div");
	var dialog_header = document.createElement("div");
	var dialog_content = document.createElement("div");
	var dialog_control = document.createElement("div");
	var dialog_lbl = document.createElement("label");
	var btnClose = new Image("images/close.png");
	dialog_content.appendChild(dialog_lbl);
	dialog_div.appendChild(dialog_header);
	dialog_div.appendChild(dialog_content);
	dialog_div.appendChild(dialog_control);
	dialog_div.setAttribute('id','dialog_div_'+id);
	dialog_header.setAttribute('id','dialog_header_'+id);
	dialog_content.setAttribute('id','dialog_content_'+id);
	dialog_control.setAttribute('id','dialog_control_'+id);
	dialog_lbl.setAttribute('id','dialog_lbl_'+id);
	document.getElementsByTagName("body")[0].appendChild(dialog_div);
	$('#dialog_lbl_'+id).html(msg);
	$('#dialog_header_'+id).html(title+btnClose.toHtml());
	if(controls != null){
		var str = "";
		for(var i=0;i<controls.length;i++){
			str += controls[i].toHtml();
		}
		$('#dialog_control_'+id).html(str);
	}
	$('#dialog_div_'+id).addClass('alert_div');
	$('#dialog_header_'+id).addClass('alert_header');
	$('#dialog_content_'+id).addClass('alert_content');
	$('#dialog_control_'+id).addClass('alert_content');
	btnClose.setStyle("float","right");
	btnClose.setStyle("margin-right","5px");
	var _width = $(window).width();
	var _height = $(window).height();	
	var _top = (_height - $("#dialog_div_"+id).height())/2;
	var _left = (_width - $("#dialog_div_"+id).width())/2;
	$("#dialog_div_"+id).css('top',_top);
	$("#dialog_div_"+id).css('left',_left);	
	$("#dialog_div_"+id).draggable();
	$("#dialog_div_"+id).css('zIndex','1000');
	btnClose.implement(new CloseDialog(id));
	return id;
}

function alertMsg(title,msg) {
	var alert_div = document.createElement("div");
	var alert_header = document.createElement("div");
	var alert_content = document.createElement("div");
	var alert_control = document.createElement("div");
	var alert_btn = document.createElement("button");
	var alert_lbl = document.createElement("label");
	alert_content.appendChild(alert_lbl);
	alert_control.appendChild(alert_btn);	
	alert_div.appendChild(alert_header);
	alert_div.appendChild(alert_content);
	alert_div.appendChild(alert_control);
	alert_div.setAttribute('id','alert_div');
	alert_header.setAttribute('id','alert_header');
	alert_content.setAttribute('id','alert_content');
	alert_control.setAttribute('id','alert_control');
	alert_btn.setAttribute('id','alert_btn');
	alert_lbl.setAttribute('id','alert_lbl');
	document.getElementsByTagName("body")[0].appendChild(alert_div);
	$('#alert_lbl').html(msg);
	$('#alert_header').html(title);
	$('#alert_btn').html('OK');
	$('#alert_div').addClass('alert_div');
	$('#alert_header').addClass('alert_header');
	$('#alert_content').addClass('alert_content');
	$('#alert_control').addClass('alert_content');
	var _width = $(window).width();
	var _height = $(window).height();	
	var _top = (_height - $("#alert_div").height())/2;
	var _left = (_width - $("#alert_div").width())/2;
	$("#alert_div").css('top',_top);
	$("#alert_div").css('left',_left);	
	$("#alert_div").draggable();
	$("#alert_div").css('zIndex','1000');
	$("#alert_btn").addClass('ij-button');
	$("#alert_btn").bind('click',function(){
		$("#alert_div").remove();
	});
}

function trimOff(txt, maxLen)	{
	txt = txt.trim();
	if (txt.length > maxLen)	{
		txt = txt.substr(0, maxLen);
		var lastIndexOf = txt.lastIndexOf(' ');
		if (lastIndexOf != -1)
			txt = txt.substr(0, lastIndexOf)+'...';
	}
	return txt;
}

function log(msg)	{
	if (window["console"] != undefined)	{
		console.log(msg);
		console.log(arguments.callee.caller);
	}
}
/**
 * A wrapper of the system properties.
 * Used for accessing the memcached namespace
 * @augments Class
 * @author griever
 */
Memcached = Class.extend({
	
	/**
	 * Initialize fields
	 * @constructor
	 */
	init: function()	{
		this.properties = SingletonFactory.getInstance(Application).getSystemProperties();
	},
	
	/**
	 * Private function.
	 * Get the actual entry name for the the specified key
	 */
	getEntryName: function(key)	{
		return 'memcached.'+key;
	},
	
	/**
	 * Store a value in the specified key
	 * @function
	 * @param {key} the key
	 * @param {value} the new value
	 */
	store: function(key, value)	{
		var entry = this.getEntryName(key);
		this.properties.set(entry, value);
	},
	
	/**
	 * Retrieve the value of the specified key
	 * @function
	 * @param {key} the key
	 * @returns {mixed} the value of the key
	 */
	retrieve: function(key)	{
		var entry = this.getEntryName(key);
		return this.properties.get(entry);
	},
	
	/**
	 * Clear the content of the specified key
	 * @function
	 * @param {key} the key
	 */
	clear: function(key)	{
		var entry = this.getEntryName(key);
		this.properties.set(entry, undefined);
	}
});
/**
 * Editor interface. 
 * Provide the following methods:
 *  - unregisterObserver(): unregister the current object, and it's no longer an observer
 *  @augments InterfaceImplementor
 *  @author longpham
 */
InlineEditorInterface = InterfaceImplementor.extend({
	
	implement: function(obj)	{
		
		obj.prototype.design = obj.prototype.design || function(obj) {
			obj.find(".dynamic-edit-content-button-fix").click(function(eventData){
				var parent = $(this).parent();
				var sibs = parent.siblings('.dynamic-edit-form'); 
				parent.hide(); 
				sibs.show();
				var tmp = $.trim(parent.find(".dynamic-edit-content-value").html());
				sibs.children('input').focus();
				sibs.children('input').val(tmp);
			});
			
			obj.find(".dynamic-edit-content-button-cancel").click(function(eventData){
				var parent = $(this).parent();
				var sibs = parent.siblings('.dynamic-edit-content');
				parent.children('input').val(""); 
				parent.hide();
				sibs.show();
			});
			// var x = obj.find(".dynamic-edit-main .row:last");
			// x.hide();
			obj.find("[level]").each(function(){
				var lev = $(this).attr("level");
				$(this).find(".dynamic-edit-main").css('margin-left', 30);
			});
			$('.dynamic-edit-content-value').filter(function() { return $(this).text() == ""; }).each(function(){
				var parent = $(this).parent();
				parent.hide();
				parent.siblings(".dynamic-edit-form").show();
			});
		};
		
		obj.prototype.encapData = obj.prototype.encapData || function(arr, tblName, id, level){
			for (var i in arr){
				arr[i]={'tbl':tblName, 'id':id, 'val':arr[i], 'level':level};
			};
		}
	}
});
/**
 * An interface for all ajax-based portlets or plugins
 * Provide the following methods:
 *  - onAjax(controller, action, params, type, callback)
 */
AjaxInterface = InterfaceImplementor.extend({
	implement: function(obj)	{
		var interfacePrivate = function(ret, success, fail, url)	{
			var result = ret.data;
			if (ret.status)	{
				if (success != undefined)	{
					try {
						success.call(undefined, result);
					} catch (err)	{
						log(err+" - "+url);
					}
				}
			} else if (result == 'exception.PrivilegeException') {
				var subject = SingletonFactory.getInstance(Subject);
				subject.notifyEvent('NotifyError', ret.msg);
			} else {
				if (fail != undefined)	{
					try {
						fail.call(undefined, ret.msg, ret.data);
					} catch (err)	{
						log(err);
					}
				}
			}
		};
		obj.prototype.onAjax = obj.prototype.onAjax || function(controller, action, params, type, callbacks, cache, cacheTime)	{
			if (type == undefined)
				type = 'GET';
			var success = callbacks.onSuccess;
			var fail = callbacks.onFailure;
			var accessDenied = callbacks.onAccessDenied;
			
			var memcacheKey = 'ajax.'+controller+'.'+action;
			for(var k in params)	{
				var v = params[k];
				memcacheKey += '.'+k+'.'+v;
			}

			var root = SingletonFactory.getInstance(Application).getSystemProperties().get('host.root');
			var url = root+'/'+controller+'/'+action;
			//try to get from mem cached
			if (type == 'GET' && cache == true)	{
				var memcache = SingletonFactory.getInstance(Memcached);
				var value = memcache.retrieve(memcacheKey);
				if (value != undefined)	{
					var now = new Date();
					var cacheTimestamp = value.timestamp;
					if ((now.getTime() - cacheTimestamp) < cacheTime)	{
						var subject = SingletonFactory.getInstance(Subject);
						subject.notifyEvent('AjaxQueryFetched', {result: value.ret, url: url});
						interfacePrivate(value.ret, success, fail, url);
						return;
					} else {
						memcache.clear(memcacheKey);
					}
				}
			}
			
			var subject = SingletonFactory.getInstance(Subject);
			$.ajax({
				dataType: 'json',
				url: url,
				type: type,
				data: params,
				success: function(ret)	{
					subject.notifyEvent('AjaxFinished');
					if (ret != null)	{
						if (type == 'GET' && cache == true)	{
							//cache the result
							var memcache = SingletonFactory.getInstance(Memcached);
							var now = new Date();
							memcache.store(memcacheKey, {'ret': ret, 'timestamp': now.getTime()});
						}
						subject.notifyEvent('AjaxQueryFetched', {result: ret, url: url});
						interfacePrivate(ret, success, fail, url);
					}
				},
				error: function(ret, textStatus)	{
					subject.notifyEvent('AjaxFinished');
				},
				statusCode: {
					403: function()	{
						//console.log('access denied at '+url);
						if (accessDenied != undefined)
							accessDenied.call(undefined);
					}
				}
			});
		};
	}
});
BKBootstrap = Bootstrap.extend({
	setupRequestHandler: function()	{
		this.requestHandler = new RequestHandler();
		this.requestHandler.setErrorHandler(new BKErrorHandler());
	}
}).implement(ObserverInterface);

BKErrorHandler = DefaultErrorHandler.extend({
	handle: function(err, event)	{
		log(err+" - "+event);
		if (typeof err == 'object')	{
			if (err.Exception == 'NotFound')	{
				var request = new Request("ErrorPage", null, {'code': 404});
				var subject = SingletonFactory.getInstance(Subject);
				subject.notifyEvent("RequestRoute", request);
			} else if (err.Exception == 'RequestInterrupted')	{
				return;
			}
		}
	}
});
SystemMessagePlugin = Class.extend({
	init: function()	{
		this.name = "SystemMessagePlugin";
		this.fetched = false;
	},
	
	onSystemPropertyChanged: function(eventData)	{
		if (eventData == 'user.login')	{
			this.fetch();
		}
	},
	
	onPageBegan: function() {
		this.fetch();
	},
	
	fetch: function() {
		if (this.fetched) return;
		this.fetched = true;
//		var subject = SingletonFactory.getInstance(Subject);
//		subject.notifyEvent('NotifyMessage', "Hiện tại hệ thống Asking.vn & BKProfile.com đang gặp 1 số vấn đề kĩ thuật nên tạm thời gián đoạn phục vụ. Chúng tôi đã tiến hành tìm hiểu nguyên nhân và sẽ thông báo lại cho bạn trong thời gian sớm nhất. <br />Nếu bạn không phiền hệ thống sẽ gửi mail active tài khoản cũ tới các bạn.Rất mong bạn thông cảm với sự cố này.<br />Xin chân thành cảm ơn!");
		
		var systemProperties = SingletonFactory.getInstance(Application).getSystemProperties();
		var loggedIn = systemProperties.get('user.login');
		if (loggedIn != 1) return;
		
		this.onAjax('user-ajax', 'get-system-message', {}, 'GET', {
			onSuccess: function(ret) {
				if (ret != null)	{
					var subject = SingletonFactory.getInstance(Subject);
					subject.notifyEvent('NotifyMessage', ret.msg);
				}
			}
		});
	}
}).implement(PluginInterface).implement(AjaxInterface);
InputMethodPlugin = Class.extend({
	init: function() {
		this.name = "InputMethodPlugin";
	},
	
	onInitInputMethod: function() {
		var AVIMObj = new AVIM();
		//function AVIMAJAXFix() {
		//	var a = 50;
		//	while(a < 5000) {
		//		setTimeout("AVIMInit(AVIMObj)", a);
		//		a += 50;
		//	}
		//}
		//AVIMAJAXFix();
		AVIMInit(AVIMObj);
		//AVIMObj.attachEvt(document, "mousedown", AVIMAJAXFix, false);
		AVIMObj.attachEvt(document, "keydown", AVIMObj.keyDownHandler, true);
		AVIMObj.attachEvt(document, "keypress", function(e) {
			var a = AVIMObj.keyPressHandler(e);
			if (a == false) {
				if (AVIMObj.is_ie) window.event.returnValue = false;
				else e.preventDefault();
			}
		}, true);
		if (!AVIMObj.support || AVIMObj.isKHTML) {
			$('#AVIMControl').addClass('disable');
			$('#AVIMControl a').addClass('disable');
			$('#AVIMControl input').attr('disabled', 'disabled');
			$('#AVIMControl').attr('title', 'Trình duyệt của bạn không hỗ trợ bộ gõ tiếng Việt');
			$('#AVIMControl-Button').hide();
		}
	}
}).implement(PluginInterface);
ScrollPlugin = Class.extend({
	init: function()	{
		this.name = "ScrollPlugin";
	},
	
	onHtmlRendered: function()	{
		$(window).scroll(function() {
			if ($(window).scrollTop() + $(window).height() == $(document).height())	{
				var subject = SingletonFactory.getInstance(Subject);
				subject.notifyEvent('GetMoreResultRows');
			}
		});
	},
	
	onEnd: function() {
		$(window).unbind('scroll');
	}
}).implement(PluginInterface);
AjaxLoadingPlugin = Class.extend({
	init: function()	{
		this.name = "AjaxLoadingPlugin";
		this.ajaxCount = 0;
	},
	
	onAjaxBegan: function()	{
		this.ajaxCount ++;
		var id = '#effective-area #AjaxLoadIndicator';
		if ($(id).length == 0)	{
			$('#effective-area').append('<div id="AjaxLoadIndicator" class="ajax-load-indicator"><img src="resource/images/ajax-loader-1.gif" /></div>');
		}
		var w = 32;
		var h = 32;
		var left = (screen.width/2)-(w/2);
		var top = (screen.height/2)-(h/2);
		$(id).attr('style', 'position: fixed; left: '+left+'px; top: '+top+'px;');
		$(id).show();
	},
	
	onAjaxFinished: function()	{
		if (this.ajaxCount > 0)	{
			this.ajaxCount --;
		}
		if (this.ajaxCount == 0)	{
			var id = '#effective-area #AjaxLoadIndicator';
			$(id).hide();
		}
	}
}).implement(PluginInterface);
GetAnnouncementPlugin = Class.extend({
	init: function()	{
		this.name = "GetAnnouncementPlugin";
	},
	
	onBegin: function()	{
		this.onGetAnnouncement();
		this.startInterval(300*1000, this.onGetAnnouncement);
	},

	onGetAnnouncement: function()	{
		this.onAjax('ajax', 'get-announcement', {}, 'GET', {
			'onSuccess': function(ret)	{
				if (ret == undefined || ret == "")
					return;
				//find if plugin already loaded
				var containerHTML = tmpl('GetAnnouncementPluginContainer', {});
				if ($('div#GetAnnouncementPlugin').length <= 0)	{
					$('div.extension-point[extensionName="PostTop"]:first').prepend(containerHTML);
				}
				$('div#GetAnnouncementPlugin').html(ret);
				$('div#GetAnnouncementPlugin').fadeOut(60000);
			}
		});
	},
	
	onEnd: function()	{
		this.stopInterval();
	}
}).implement(PluginInterface).implement(IntervalTimerInterface).implement(AjaxInterface);

GlobalNotificationPlugin = Class.extend({
	init: function()	{
		this.name = "GlobalNotificationPlugin";
	},
	
	onCloseGlobalNotify: function()	{
		$('div#action_msg').stop().animate({opacity: '100'}).hide();
	},
	
	onNotifyGlobal: function(eventData)	{
		$('#msg_content').html(eventData);
		$('div#action_msg').stop().animate({opacity: '100'});
		$('div#action_msg').show().fadeOut(15000);
	}
}).implement(PluginInterface).implement(IntervalTimerInterface).implement(AjaxInterface);

PopupPlugin = Class.extend({
	init: function()	{
		this.name = "PopupPlugin";
		this.popup = new Popup();
	},
	
	onOperationNotSupported: function(eventData) {
		this.popup.msg("Chức năng này đang trong quá trình xây dựng. Bạn vui lòng thử lại sau");
	},
	
	onPopupRemove: function(eventData)	{
		var id = eventData.id;
		this.popup.remove(id);
	},
	
	onShowPopup: function(eventData)	{
		this.popup.add(eventData.id, eventData.title, eventData.content);
	},
	
	onNotifyMessage: function(eventData)	{
		this.popup.msg(eventData);
	},
	
	onNotifyError: function(eventData)	{
		this.popup.error(eventData);
	}
}).implement(PluginInterface);

KeepAlivePlugin = Class.extend({
	init: function()	{
		this.name = "KeepAlivePlugin";
	},
	
	onBegin: function()	{
		this.onKeepAlive();
		this.startInterval(5*60*1000, this.onKeepAlive);
	},

	onKeepAlive: function()	{
		this.onAjax('ajax', 'check-user-status', {}, 'GET', {
			'onSuccess': function(ret)	{
				
			}
		});
	},
	
	onEnd: function()	{
		this.stopInterval();
	}
}).implement(PluginInterface).implement(IntervalTimerInterface).implement(AjaxInterface);
AnswerShowBioPlugin = Class.extend({
	init: function()	{
		this.name = "AnswerShowBioPlugin";
	},
	
	onBegin: function()	{
		this.catches = undefined;
	},
	
	onShowBio: function(eventData)	{
		var memcached = SingletonFactory.getInstance(Memcached);
		var keyToStore = "question.catchword";
		if (eventData.qid != this.qid)	{
			this.catches = undefined;
		}
		memcached.clear(keyToStore);
		this.qid = eventData.qid;
		var obj = this;
		if (obj.catches == undefined)	{
			obj.onAjax('question', 'get-all-catchwords-question', {'qid': obj.qid}, 'GET', {
				'onSuccess': function(ret)	{
					memcached.store(keyToStore, ret);
					obj.catches = ret;
					obj.renderBios();
				}
			}, true, 300000);
		} else {
			obj.renderBios();
		}
	},
	
	renderBios: function()	{
		var obj = this;
		$('.extension-point[extensionName="AnswerProfileName"]').each(function(index, value) {
			if ($(value).find('[flag="AnswerShowBio"]').length > 0)	{
				return;
			}
			$(value).append('<span flag="AnswerShowBio"></span>');
			var uid = $(value).attr('extensionId');
			obj.renderBio(value, uid);
		});
	},
	
	renderBio: function(value, uid)	{
		var obj = this;
		this.onAjax('user-ajax', 'get-all-expertises', {'id': uid}, 'GET', {
			'onSuccess': function(ret)	{
				for(var i in obj.catches)	{
					var cat = obj.catches[i];
					var catId = cat.id;
					for (var j in ret)	{
						var retJ = ret[j];
						for (var k in retJ)	{
							var retJK = retJ[k];
							if (catId == retJK.catchWordId)	{
								var explanation = retJK.explanation;
								$(value).prepend(tmpl('AnswerShowBioTmpl', {'content': explanation}));
								return;
							}
						}
					}
				}
			}
		}, true, 300000);
	}
}).implement(PluginInterface).implement(AjaxInterface);

AnswerEditBioPlugin = Class.extend({
	init: function()	{
		this.name = "AnswerEditBioPlugin";
	},
	
	onBegin: function()	{
		this.catches = undefined;
	},
	
	onRenderBioEditLink: function(eventData)	{
		var qid = eventData.qid;
		$('.extension-point[extensionName="AnswerProfileName"]').each(function(index, value) {
			if ($(value).find('[flag="AnswerEditBio"]').length > 0)	{
				return;
			}
			var properties = SingletonFactory.getInstance(Application).getSystemProperties();
			var loggedIn = properties.get('user.login');
			if (loggedIn == 1)	{
				var userID = properties.get('user.id');
				var answerUID = $(value).attr('extensionID');
				if (userID == answerUID)	{
					$(value).append(tmpl('AnswerEditBioTmpl', {'qid':qid}));
				}
			}
		});
	},
	
	onEditBioClick: function(eventData)	{
		this.qid = eventData.qid;
		var obj = this;
		if (this.catches == undefined)	{
			var keyToGet = "question.catchword";
			var memcached = SingletonFactory.getInstance(Memcached);
			var catches = memcached.retrieve(keyToGet);
			if (catches != undefined)	{
				this.catches = catches;
				this.prepareShowingBioEditor();
			} else {
				obj.onAjax('question', 'get-all-catchwords-question', {'qid': obj.qid}, 'GET', {
					'onSuccess': function(ret)	{
						memcached.store(keyToGet, ret);
						obj.catches = ret;
						obj.prepareShowingBioEditor();
					}
				}, true, 300000);
			}
		} else {
			this.prepareShowingBioEditor();
		}
	},
	
	prepareShowingBioEditor: function()	{
		var obj = this;
		var memcached = SingletonFactory.getInstance(Memcached);
		var currentExpertises = memcached.retrieve('user.expertises');
		this.currentExpertises = currentExpertises;
		if (currentExpertises == undefined)	{
			this.onAjax('user-ajax', 'get-all-expertises', {}, 'GET', {
				'onSuccess': function(ret)	{
					memcached.store('user.expertises', ret);
					obj.currentExpertises = ret;
					obj.showBioEditor();
				}
			}, true, 300000);
		} else {
			this.showBioEditor();
		}
	},
	
	showBioEditor: function()	{
		var obj = this;
		var expToShow = Array();
		var ret = obj.currentExpertises;
		for(var i in obj.catches)	{
			var found = false;
			var cat = obj.catches[i];
			var catId = cat.id;
			for (var j in ret)	{
				var retJ = ret[j];
				for (var k in retJ)	{
					var retJK = retJ[k];
					if (catId == retJK.catchWordId)	{
						if (retJ[k].explanation == undefined)
							retJ[k].explanation = "";
						var plhd = tmpl('AnswerBioEditorExplanationTmpl', {'expertiseName':retJ[k].catchWord, 'expertiseExplanation':retJ[k].explanation});
						expToShow.push({'id':retJK.catchWordId,'expertiseName': retJ[k].catchWord, 'expertisePlaceholder': plhd});
						found = true;
					}
				}
			}
			if (!found)	{
				var plhd = tmpl('AnswerBioEditorExplanationTmpl', {'expertiseExplanation': undefined, 'expertiseName':cat.catchWord});
				expToShow.push({'id':cat.id,'expertiseName': cat.catchWord, 'expertisePlaceholder': plhd});
			}
		}
		var subject = SingletonFactory.getInstance(Subject);
		if (expToShow.length == 0)	{
			subject.notifyEvent('NotifyMessage', 'Câu hỏi hiện tại không thuộc chủ đề nào. Do đó bạn chưa thể thay đổi chú thích ngay bây giờ');
		} else {
			subject.notifyEvent('ShowPopup', {id: 'AnswerEditBio', title: 'Sửa chú thích cho câu trả lời', content: tmpl('AnswerBioEditorTmpl', {'expertises':expToShow})});
		}
	},
	
	onBioEditorEditClick: function(event)	{
		var target = event.event.target;
		var mode = event.mode;
		var parent = $(target).parent();
		var oldHtml = $(parent).find('.explanationPlaceholder').html();
		$(parent).html(tmpl('AnswerBioEditorExplanationEditTmpl', {'content': oldHtml, 'mode':mode}));
		$(parent).find('textarea').focus();
	},
	
	onBioEditCancelClick: function(event)	{
		var target = event.target;
		var parent = $(target).parent();
		var textBox = $(parent).find('textarea');
		$(parent).html(tmpl('AnswerBioEditorExplanationTmpl', {'expertiseExplanation':$(textBox).attr('oldVal'), 'expertiseName':$(parent).attr('expertiseName')}));
	},
	
	onBioEditUpdateClick: function(event)	{
		var target = event.event.target;
		var mode = event.mode;
		var parent = $(target).parent();
		var textBox = $(parent).find('textarea');
		var newVal = $(textBox).val();
		var oldVal = $(textBox).attr('oldVal');
		if (newVal == oldVal)	{
			$(parent).html(tmpl('AnswerBioEditorExplanationTmpl', {'expertiseExplanation':oldVal, 'expertiseName':$(parent).attr('expertiseName')}));
		} else {
			var id = $(parent).attr('expertiseID');
			if (mode == 'update')	{
				this.onAjax('user-ajax', 'update-single-expertise', {'id': id, 'explanation':newVal}, 'POST', {});
			} else {
				this.onAjax('user-ajax', 'add-single-expertise', {'id': id, 'explanation':newVal}, 'POST', {});
			}
			$(parent).html(tmpl('AnswerBioEditorExplanationTmpl', {'expertiseExplanation':newVal, 'expertiseName':$(parent).attr('expertiseName')}));
		}
	}
}).implement(PluginInterface).implement(AjaxInterface);
AskUserPlugin = Class.extend({
	init: function()	{
		this.name = "AskUserPlugin";
	},
	
	onMakeNewTargetedQuestion: function(eventData)	{
		var subject = SingletonFactory.getInstance(Subject);
		var profileName = $(eventData.target).parents('.stat_outer:first').siblings('.user-name').html();
		var pid = SingletonFactory.getInstance(Page).getRequest().getParam('id');
		subject.notifyEvent('MakeNewQuestion', {profile: [{name: profileName, id: pid}]});
	},
	
	onHtmlUpdated: function()	{
		$('.extension-point[extensionName="BriefInfoControl"]').each(function()	{
			var props = SingletonFactory.getInstance(Application).getSystemProperties();
			var loggedIn = props.get('user.login');
			var pid = undefined;
			if (loggedIn == 1)	{
				var uid = props.get('user.id');
				pid = SingletonFactory.getInstance(Page).getRequest().getParam('id');
				if (uid == pid)		{	//same user
					return;
				}
			} else {
				return;
			}
			if ($(this).find('.[flag="AskUser"]').length > 0)	{
				return;
			}
			$(this).append(tmpl('AskUserPluginTmpl', {}));
		});
	}
}).implement(PluginInterface);
AutocompletePlugin = Class.extend({
	init: function()	{
		this.name = "AutocompletePlugin";
	},
	
	onNeedAutocomplete: function(eventData)	{
		var subject = SingletonFactory.getInstance(Subject);
		var url = eventData.autocompleteSource;
		var obj = eventData.autocompleteObject;
		var type = eventData.type;
		if (type == undefined)	{
			type = 'Expertise';
		}
		
		if (eventData.fetchSourceCallback != undefined)
			subject.notifyEvent(eventData.fetchSourceCallback);
		$(obj).autocomplete({
			source: function(req, add){
				var term = $(obj).val();
				req.q = term;
				req.wt = 'json';
				$.getJSON(url, req, function(data) {
					var suggestions = [];
					data = data.response.docs;
					$.each(data, function(i, val){
						if (type == 'Expertise')
							suggestions.push({label:val['catch'], value:val.catch_id, type: 'expertise', follow: val.catch_follow});
						else if (type == 'Question')
							suggestions.push({label: val.question, value: val.questionId, type: 'question', catchwords: val.catchWords});
						else
							suggestions.push({label: val.full_name, value: val.profile_id, type: 'person', catchwords: val.expertise, avatar: val.avatar, ans: val.expertise_total_ans_count});
					});
					if (type == 'RecommendPerson')	{
						var askMsg = 'Không tìm thấy? Mời trả lời qua email';
						suggestions.push({label: askMsg, value: askMsg, type: 'email'});
					}
					add(suggestions);
				});
			},
			focus:  function(e,ui){
				if (eventData.focusCallback != undefined)
					subject.notifyEvent(eventData.focusCallback, {'ui':ui});
			},
			select: function(e,ui){
				if (eventData.selectCallback != undefined)
					subject.notifyEvent(eventData.selectCallback, {'ui':ui});
			},
			result: function(e, ui)	{
				if (eventData.resultCallback != undefined)
					subject.notifyEvent(eventData.resultCallback, {'ui':ui});
			}
		});
	}
}).implement(PluginInterface);
AutocompleteSearcherPlugin = Class.extend({
	init: function()	{
		this.name = "AutocompleteSearcherPlugin";
	},
	
	onChangeAutocompleteType: function(eventData)	{
		var type = eventData.type;
		var target = eventData.target;
		var subject = SingletonFactory.getInstance(Subject);
		
		if (type == 'person')
			subject.notifyEvent('AttachFocusDetection', {'target': $(target), 'defaultValue': 'Nhập vào từ khóa cho người bạn muốn tìm'});
		else
			subject.notifyEvent('AttachFocusDetection', {'target': $(target), 'defaultValue': 'Tìm kiếm trước khi đặt câu hỏi'});
		subject.notifyEvent('AttachAutocompleteEngine', eventData);
	},
	
	onAttachAutocompleteEngine: function(eventData)	{
		this.autocompleteEngine = SingletonFactory.getInstance(AutocompleteEngineFactory).build(eventData.type);
		$(eventData.target).autocomplete(this.autocompleteEngine);
	},
	
	onHtmlRendered: function()	{
		var selected = $("#SearcherPortlet-Select option:selected");
		var id = selected.attr('value');
		
		var subject = SingletonFactory.getInstance(Subject);
		if (id == 1)	{
			subject.notifyEvent('ChangeAutocompleteType', {type: 'person', target: $('#SearcherPortlet-Input')});
		} else {
			subject.notifyEvent('ChangeAutocompleteType', {type: 'question', target: $('#SearcherPortlet-Input')});
		}
		
		//add click handler to friends div
		$("#friends").click(function(){
			//focus 'to' field
			$("#SearcherPortlet-Input").focus();
		});
		
		//add live handler for clicks on remove links
		$(".remove", document.getElementById("friends")).live("click", function(){
			//remove current friend
			$(this).parent().remove();
			
			//correct 'to' field position
			if($("#friends span").length === 0) {
				$("#SearcherPortlet-Input").css("top", 0);
			}
		});
	}
}).implement(PluginInterface);

AutocompleteEngineFactory = Class.extend({
	build: function(type)	{
		if (type == 'person')	{
			return new PersonAutocomplete();
		} else if (type== 'question') {
			return new QuestionAutocomplete();
		} else {
			return new QuestionOnlyAutocomplete();
		}
	}
});

PersonAutocomplete = Class.extend({
	source: function(req, add){
		var solrRoot = SingletonFactory.getInstance(Application).getSystemProperties().get('host.solr');
		$.getJSON(solrRoot+"/person/person", {wt:'json', rows: '10', q: req.term}, function(data) {
			data = data.response.docs;
			var suggestions = [];
			$.each(data, function(i, val){
				suggestions.push({label: val.full_name, value: val.profile_id, type: 'person', catchwords: val.expertise, avatar: val.avatar, ans: val.expertise_total_ans_count});
			});
			
			//pass array to callback
			add(suggestions);
		});
	},
	
	//define select handler
	select: function(e, ui) {
		onClickPerson(ui.item.id);
	},
	
	//define select handler
	change: function() {
		//prevent 'to' field being updated and correct position
		$("#toPerson").css("top", 2);
	}
});

QuestionAutocomplete = Class.extend({
	//define callback to format results
	source: function(req, add){
		//pass request to server
		var solrRoot = SingletonFactory.getInstance(Application).getSystemProperties().get('host.solr');
		$.getJSON(solrRoot+"/autocomplete/autocomplete", {wt:'json', rows: '8', q: req.term}, function(data) {
			data = data.response.docs;
			//create array for response objects
			var suggestions = [];
			//process response
			$.each(data, function(i, val){
				if (val.catch_id != undefined)	{
					suggestions.push({label: val['catch'], value: val.catch_id, type: 'expertise', follow: val.catch_follow});	
				} else if (val.questionId != undefined){
					suggestions.push({label: val.question, value: val.questionId, type: 'question', catchwords: val.catchWords});
				}
			});
			
			var askMsg = req.term;
			suggestions.push({label: askMsg, value: askMsg, type: 'ask'});
			
			//pass array to callback
			add(suggestions);
		});
	},
	
	//define select handler
	select: function(e, ui) {
		//create formatted friend
		var friend = ui.item.value;
		if (ui.item.type === "expertise"){
			moveToTopic(ui.item.id);
		} else if (ui.item.type == 'ask') {
			makeQuestion(friend);
		} else {
			try {
				var tmp = $("a[question='"+escape(friend)+"']");
				moveToAQuestion(tmp.attr("question_id"));
			} catch (e) {
			}
		}
	},
	
	//define select handler
	change: function() {
		//prevent 'to' field being updated and correct position
		$("#SearcherPortlet-Input").css("top", 2);
	}
});

QuestionOnlyAutocomplete = Class.extend({
	//define callback to format results
	source: function(req, add){
		//pass request to server
		var solrRoot = SingletonFactory.getInstance(Application).getSystemProperties().get('host.solr');
		$.getJSON(solrRoot+"/autocomplete/question", {wt:'json', rows: '5', q: req.term}, function(data) {
			data = data.response.docs;
			//create array for response objects
			var suggestions = [];
			//process response
			$.each(data, function(i, val){
				suggestions.push({label: val.question, value: val.questionId, type: 'question', catchwords: val.catchWords});
			});
			
			var askMsg = req.term;
			suggestions.push({label: askMsg, value: askMsg, type: 'ask'});
			
			//pass array to callback
			add(suggestions);
		});
	},
	
	//define select handler
	select: function(e, ui) {
		//create formatted friend
		var friend = ui.item.value;
		if (ui.item.type === "expertise"){
			moveToTopic(ui.item.id);
		} else if (ui.item.type == 'ask') {
			makeQuestion(friend);
		} else {
			try {
				var tmp = $("a[question='"+escape(friend)+"']");
				moveToAQuestion(tmp.attr("question_id"));
			} catch (e) {
			}
		}
	},
	
	//define select handler
	change: function() {
		//prevent 'to' field being updated and correct position
		$("#SearcherPortlet-Input").css("top", 2);
	}
});

function onClickPerson(id){
	var subject = SingletonFactory.getInstance(Subject);
    var request = new Request("Profile", undefined,{id: id});
    subject.notifyEvent('RequestRoute', request);
}

function moveToAQuestion(question_id){
	var qid = question_id;
	var subject = SingletonFactory.getInstance(Subject);
    var request = new Request("Question","donganh",{"qid":qid});
    subject.notifyEvent('RequestRoute', request);
}

function moveToTopic(id){
	var subject = SingletonFactory.getInstance(Subject);
    var request = new Request("Topic", undefined, {'id':id});
    subject.notifyEvent('RequestRoute', request);
}

function makeQuestion(ques){
	var subject = SingletonFactory.getInstance(Subject);
	subject.notifyEvent("MakeNewQuestion", {question: ques});
}
AvatarEditPlugin = Class.extend({
	init: function()	{
		this.name = "AvatarEditPlugin";
	},
	
	onReloadPlugin: function()	{
		this.renderAvatar();
	},
	
	onAvatarInputChange: function()	{
		$('#AvatarUploaderContainer').submit();
	},
	
	renderAvatar: function()	{
		$('.extension-point[extensionName="avatar"]').each(function(index, value)	{
			if ($(value).find('div[flag="AvatarUploader"]').length>0)
				return;
			var root = SingletonFactory.getInstance(Application).getSystemProperties().get('host.root');
			$(value).append(tmpl('AvatarUploader', {'root': root}));
			$('#AvatarUploaderContainer').submit(function() {
				var fr = $('#avatar-upload-frame');
				$(fr).one('load', function() {
					var response = fr.contents().find('body').html();
					$('AvatarUploaderContainer').find('input[type="submit"]').attr('disabled', '');
			    	var ret = $.parseJSON(response);
			    	$(value).find('#AvatarUploaderErrorPlaceholder').html('');
			    	if (!ret.status)	{
			    		errors = {};
			    		errors.errors = ret.msg; 
			    		$(value).find('#AvatarUploaderErrorPlaceholder').html(tmpl('AvatarUploaderError', errors));
			    	} else {
			    		$('#BriefInfoEditPortlet-Avatar').find('img').remove();
			    		$('#BriefInfoEditPortlet-Avatar').html('<img style="width: 100px" src="resource/avatar/'+ret.data+'" />');
		    			var subject = SingletonFactory.getInstance(Subject);
		    			subject.notifyEvent('NotifyGlobal', 'Bạn đã thay đổi avatar thành công. Nếu ảnh chưa hiện ra, hãy ấn F5 để thấy sự thay đổi');
			    	}
				});
			});
		});
	},
	
	onHtmlUpdated: function()	{
		this.renderAvatar();
	}
}).implement(PluginInterface);
FollowUserPlugin = Class.extend({
	init: function()	{
		this.name = "FollowUserPlugin";
	},
	
	onUnfollowUser: function(eventData)	{
		var uid = eventData.uid;
		var containerID = eventData.containerID; 
		this.onAjax('user-ajax', 'unfollow-user', {'uid': uid}, 'POST', {
			'onSuccess': function(ret)	{
				//Find the container with attribute uid == uid
				$("." + containerID).each(function(){
					if($(this).attr('uid') == uid)
						$(this).html(tmpl('FollowUserTmpl-Follow', {uid: uid,containerID:containerID}));
				});
				var subject = SingletonFactory.getInstance(Subject);
				subject.notifyEvent("FollowersChange", {});
			}
		});
	},
	
	onFollowUser: function(eventData)	{
		var uid = eventData.uid;
		var containerID = eventData.containerID; 
		this.onAjax('user-ajax', 'follow-user', {'uid': uid}, 'POST', {
			'onSuccess': function(ret)	{
				//Find the container with attribute uid == uid
				$("." + containerID).each(function(){
					if($(this).attr('uid') == uid){
						$(this).html(tmpl('FollowUserTmpl-Unfollow', {uid: uid,containerID: containerID}));
					}
				});
				var subject = SingletonFactory.getInstance(Subject);
				subject.notifyEvent("FollowersChange", {});
			}
		});
	},
	
	onFollowUserList: function(eventData){
		var props = SingletonFactory.getInstance(Application).getSystemProperties();	
		var currUID = props.get('user.id');
		var containerID = eventData.containerID ;
		var obj = this;
		//for all container of each follower
		$("div."+containerID).each(function()	{
			var objSelector = $(this); 
			var uid = objSelector.attr('uid');
			if(currUID == uid)
				return;
			obj.onAjax('user-ajax', 'is-user-following-user', {'uid': uid}, 'GET', {
			'onSuccess': function(ret)	{
				var follow = '';
				if (ret == true)	{
					follow = 'Unfollow';
				} else {
					follow = 'Follow';
				}
				//add button into this container
				objSelector.html(tmpl('FollowUserTmpl-'+follow, {uid: uid, containerID: containerID}));
			}//end OnSuccess
			});//end onAjax
		});//end Each
	
	},
	
	onReloadPlugin: function() {
		this.fetched = false;
	},
	
	onHtmlUpdated: function(eventData)	{
		var props = SingletonFactory.getInstance(Application).getSystemProperties();
		var loggedIn = props.get('user.login');
		var pid = undefined;
		if (loggedIn == 1)	{
			var uid = props.get('user.id');
			pid = SingletonFactory.getInstance(Page).getRequest().getParam('id');
			if (uid == pid)		{	//same user
				return;
			}
		} else {
			return;
		}
		if(this.fetched == true)	{
			this.renderWidget(this.isFollow, pid);
			return;
		}
		var obj = this;
		this.onAjax('user-ajax', 'is-user-following-user', {'uid': pid}, 'GET', {
			'onSuccess': function(ret)	{
				obj.fetched = true;
				obj.renderWidget(ret, pid);
			}//end OnSuccess
		});//end onAjax
	},
	
	renderWidget: function(ret, pid) {
		var follow = '';
		this.isFollow = ret;
		if (ret == true)	{
			follow = 'Unfollow';
		} else {
			follow = 'Follow';
		}
		$('.extension-point[extensionName="BriefInfoControl"]').each(function()	{
			if ($(this).find('[flag="FollowUser"]').length > 0)	{
				return;
			}
			$(this).append(tmpl('FollowUserTmpl', {uid: pid}));
			$('.followuser_container').html(tmpl('FollowUserTmpl-'+follow, {uid: pid,containerID:"followuser_container"}));
		});//end Each
	}
}).implement(PluginInterface).implement(AjaxInterface);
UserTabGeneratorPlugin = Class.extend({
	init: function()	{
		this.name = "UserTabGeneratorPlugin";
		this.ids = new Array("User","UserFeed","UserQuestion","UserTarget","UserAnswer","UserBookmark","UserReportedQuestions");
	},
	
	onHtmlUpdated: function()	{
		var request = SingletonFactory.getInstance(Page).getRequest();
		var page = request.getParam("page");
		var plugin = this;
		if ($('#UserTabGeneratorPlaceholder').length <= 0)	{
			var template = $(tmpl('UserTabGeneratorPlaceholder-Tmpl', {}));
			$('.extension-point[extensionName="ProfileTab"]').append(template);
			var count = 0;
			$('.extension-point[extensionName="ProfileTab"]').find(".user-tab a").each(function(){
				count++;
				if(plugin.ids[count-1] != page){
					$(this).removeClass("active");
				} else {
					$(this).addClass("active");
				}
				var curID = "userTab-" + count;
				$(this).attr("id",curID);
				$(this).attr("onClick","generateEvent('UserTabGeneratorChange',{id:'"+curID+"'})");
			});
		}else{
			for( var i=0; i<this.ids.length; i++ )	{
				if($('#userTab-'+(i+1)).hasClass("active")){
					$('#userTab-'+(i+1)).removeClass("active");
				}
				if(!$('#userTab-'+(i+1)).hasClass("active")){
					$('#userTab-'+(i+1)).addClass("active");
				}
			}
			
			for( var i=0; i<this.ids.length;i++ )	{
				if(this.ids[i] == page){
					$('#userTab-'+(i+1)).addClass("active");
				}else{
					$('#userTab-'+(i+1)).removeClass("active");
				}
			}
		}
	},
	
	onEnd: function()	{
		if ($('#UserTabGeneratorPlaceholder').length > 0)
			$('#UserTabGeneratorPlaceholder').remove();
	}
}).implement(PluginInterface);

UserEditMenuGeneratorPlugin = Class.extend({
	init: function()	{
		this.name = "UserEditMenuGeneratorPlugin";
		this.ids = new Array("PartnerProfileEdit", "UserAvatarEdit", "UserExpertiseEdit", "UserInterestEdit");
	},
	
	onHtmlUpdated: function()	{
		var request = SingletonFactory.getInstance(Page).getRequest();
		var page = request.getParam("page");
		var plugin = this;
		if ($('#UserEditMenu').length <= 0)	{
			var template = $(tmpl('UserEditMenuTmpl', {}));
			$('.extension-point[extensionName="MiddleMain"]').append(template);
			var count = 0;
			$('.extension-point[extensionName="MiddleMain"]').find(".user-tab a").each(function(){
				count++;
				if(plugin.ids[count-1] != page){
					$(this).removeClass("active");
				} else {
					$(this).addClass("active");
				}
				var curID = "userEditTab-" + count;
				$(this).attr("id",curID);
			});
		}else{
			for( var i=0; i<this.ids.length; i++ )	{
				if($('#userEditTab-'+(i+1)).hasClass("active")){
					$('#userEditTab-'+(i+1)).removeClass("active");
				}
				if(!$('#userEditTab-'+(i+1)).hasClass("active")){
					$('#userEditTab-'+(i+1)).addClass("active");
				}
			}
			
			for( var i=0; i<this.ids.length;i++ )	{
				if(this.ids[i] == page){
					$('#userEditTab-'+(i+1)).addClass("active");
				}else{
					$('#userEditTab-'+(i+1)).removeClass("active");
				}
			}
		}
		
		if (request.getParam('msg') == 'reg_complete')	{
			$('#UserEditMenu-Msg').html('<div class="green_box">Quá trình đăng ký đã hoàn tất. Bạn có thể sửa thông tin cá nhân ngay bây giờ.<br /><a href="#" class="bold">Click vào đây để quay lại trang chủ</a></div>');
		}
	},
	
	onEnd: function()	{
		if ($('#UserEditMenu').length > 0)
			$('#UserEditMenu').remove();
	}
}).implement(PluginInterface);

ProfileTabGeneratorPlugin = UserTabGeneratorPlugin.extend({
	init: function()	{
		this.name = "ProfileTabGeneratorPlugin";
		this.ids = new Array("Profile","ProfileFeed","ProfileQuestion","ProfileTarget","ProfileAnswer","ProfileBookmark","ProfileReportedQuestions");
	},
	
	onReloadPlugin: function()	{
		//remove old tab
		if ($('#ProfileTabGeneratorPlaceholder').length > 0)
			$('#ProfileTabGeneratorPlaceholder').remove();
		this.renderTab();
	},
	
	onHtmlUpdated: function()	{
		this.renderTab();
	},
	
	renderTab: function()	{
		var request = SingletonFactory.getInstance(Page).getRequest();
		var params = request.getParams();
		var page = request.getParam("page");
		if ($('#ProfileTabGeneratorPlaceholder').length <= 0)	{
			var id = params['id'] || undefined;
			var objParam = {};
			if (id != undefined){
				objParam.id = id;
			}
			
			var template = $(tmpl('ProfileTabGeneratorPlaceholder-DATmpl', objParam));
			var count = 0;
			var plugin = this;
			$('div.extension-point[extensionName="ProfileTab"]').each(function()	{
				$(this).append(template);
				$('.user-tab-item').removeClass('active');
				$(this).find(".user-tab a").each(function(){
					count++;
					if(plugin.ids[count-1] == page){
						$(this).addClass("active");
					}
					var curID = "userTab-" + count;
					$(this).attr("id",curID);
					$(this).addClass('user-tab-item');
				});
			});
		}
	},
	
	onEnd: function()	{
		if ($('#ProfileTabGeneratorPlaceholder').length > 0)
			$('#ProfileTabGeneratorPlaceholder').remove();
	}
}).implement(PluginInterface);

PartnerProfileTabGeneratorPlugin = UserTabGeneratorPlugin.extend({
	init: function()	{
		this.name = "PartnerProfileTabGeneratorPlugin";
		this.ids = new Array("PartnerProfile","PartnerProfileNews","PartnerProfileTarget","PartnerProfileAnswer");
	},
	
	onReloadPlugin: function()	{
		//remove old tab
		if ($('#MockupProfileTabGeneratorPlaceholder').length > 0)
			$('#MockupProfileTabGeneratorPlaceholder').remove();
		this.renderTab();
	},
	
	onHtmlUpdated: function()	{
		this.renderTab();
	},
	
	renderTab: function()	{
		var request = SingletonFactory.getInstance(Page).getRequest();
		var params = request.getParams();
		var page = request.getParam("page");
		if ($('#MockupProfileTabGeneratorPlaceholder').length <= 0)	{
			var id = params['id'] || undefined;
			var objParam = {};
			if (id != undefined){
				objParam.id = id;
			}
			
			var template = $(tmpl('MockupProfileTabGenerator-Tmpl', objParam));
			var count = 0;
			var plugin = this;
			$('div.extension-point[extensionName="MockupProfileTab"]').each(function()	{
				$(this).append(template);
				$('.user-tab-item').removeClass('active');
				$(this).find(".user-tab a").each(function(){
					count++;
					if(plugin.ids[count-1] == page){
						$(this).addClass("active");
					}
					var curID = "userTab-" + count;
					$(this).attr("id",curID);
					$(this).addClass('user-tab-item');
				});
			});
		}
	},
	
	onEnd: function()	{
		if ($('#MockupProfileTabGeneratorPlaceholder').length > 0)
			$('#MockupProfileTabGeneratorPlaceholder').remove();
	}
}).implement(PluginInterface);

ProfileSearchHeaderPlugin = Class.extend({
	init: function()	{
		this.name = "ProfileSearchHeaderPlugin";
	},
	
	setupParameters: function()	{
		this.request = SingletonFactory.getInstance(Page).getRequest();
		this.label = '';
		this.style = 'grey_title';
		
		switch(this.request.getParam('page'))	{
		case 'ProfileQuestion':
		case 'UserQuestion':
			this.label = 'Các câu đã hỏi';
			break;
		case 'ProfileTarget':
		case 'UserTarget':
			this.label = 'Các câu được hỏi';
			break;
		case 'ProfileAnswer':
		case 'UserAnswer':
			this.label = 'Các câu đã trả lời';
			break;
		case 'Topic':
			this.label = 'Các câu hỏi trong chủ đề';
			break;
		case 'Introduce':
			this.label = 'Các câu hỏi mới cập nhật';
			this.style='browse_title';
			break;
		}
	},
	
	onBegin: function()	{
		this.setupParameters();
	},
	
	onReloadPlugin: function()	{
		this.setupParameters();
	},
	
	onHtmlUpdated: function()	{
		var label = this.label;
		var style = this.style;
		$('div.extension-point[extensionName="SearchResultTitle"]').each(function()	{
			if ($(this).find('[flag="ProfileSearchHeader"]').length > 0)
				return;
			$(this).append(tmpl('ProfileSearchHeaderTmpl', {label: label, style: style}));
		});
	}
}).implement(PluginInterface);

TopMenuNavPlugin = Class.extend({
	init: function()	{
		this.name = "TopMenuNavPlugin";
	},
	
	onHtmlRendered: function() {
		var page = SingletonFactory.getInstance(Page);
		$('a[page]').removeClass('active');
		$('a[page="'+page.pagename+'"]').addClass('active');
	}
}).implement(PluginInterface);

QuestionFollowPlugin = Class.extend({
	init: function()	{
		this.name = "QuestionFollowPlugin";
	},
	
	
}).implement(PluginInterface).implement(AjaxInterface);
AnswerEditPlugin = Class.extend({
	init : function() {
		this.name = "AnswerEditPlugin";
		this.app = SingletonFactory.getInstance(Application);
		this.props = this.app.getSystemProperties();
		this.root = this.app.getSystemProperties().get("host.root");
	},
	
	checkUserLogin : function(eventData, type) {
		var evtArgs = {};
		evtArgs.type = type;
		evtArgs.evtData = eventData;
		var sbj = SingletonFactory.getInstance(Subject);
		sbj.notifyEvent("NeedLogin", evtArgs);
	},
	
	onSubmitAnswer : function(eventData) {
		this.checkUserLogin(eventData, "SubmitAnswer");
	},
	
	onLoginSuccess : function(eventData) {
		var type = eventData.type;
		var evtArgs = eventData.evtData;
		if (type != undefined && evtArgs != undefined) {
			switch (type) {
				case "SubmitAnswer":
					this.submitAnswer(evtArgs);
					break;
				default:
					break;
			}
		}
	},

	submitAnswer : function(eventData) {
		var request = SingletonFactory.getInstance(Page).getRequest();
		var params = request.getParams();
		var qid = params['qid'];
		if (qid == undefined) {
			return;
		}
		var sbj = this.props.get("memcached.answeredID");
		var userid = this.props.get("user.id");
		if (sbj != undefined && userid != undefined) {
			for (var key in sbj) {
				var curID = sbj[key];
				if (curID == userid) {
					return;
				}
			}
		}
		var sbj = SingletonFactory.getInstance(Subject);

		var mceID = eventData.id;
		var instance = this.props.get("memcached.tinyeditor");
		var content = instance[mceID].e.body.innerHTML;
		var obj = this;
		this.onAjax('answer', 'add', {qid : qid, content : content}, 'POST', {
			'onSuccess' : function(ret) {
				instance[mceID].e.body.innerHTML = "";
				$('#AnswerPortlet-TextAreaContainer').html('');
				$('#AnswerPortlet-TextAreaContainer').hide();
				sbj.notifyEvent('ReloadAnswers');
			}
		});
	},
	
	checkImage: function(html){
		var parent = $("<div></div>");
		$(parent).append(html);
		var tmp = $(parent).find("img").each(function(index,value){
			var imgSrc = $(value).attr("src");
			
			var newImg = new Image();
			newImg.src = imgSrc;
			var height = newImg.height;
			var width = newImg.width;
			if(height == 0 || width == 0 || imgSrc == ""){
				$(value).remove();
			}
			if(width >= 400){
				$(value).attr('width','400');
			}
			$(value).css("vertical-align","middle");
			$(value).css("display","block");
			var subTmp = $("<center></center>");
			var valueTmp = $(value).clone();
			$(value).replaceWith($(subTmp).append($(valueTmp)));
		});
		return $(parent).html();
	},
	
	onEditAnswerSubmit: function(eventData)	{
		var uid = eventData.uid;
		var aid = eventData.aid;
		var mceID = "OwnAnswerEditor-" + uid + "-" + aid;
		var instance = SingletonFactory.getInstance(Application).getSystemProperties().get("memcached.tinyeditor");
		var content = instance[mceID].e.body.innerHTML;
		content = this.checkImage(content);
		var notify = $('#OwnAnswerEditor-NotifyFollowers').is(':checked') ? 1 : 0;

		var sbj = SingletonFactory.getInstance(Subject);
		this.onAjax('answer', 'update', {aid: aid, content: content, notify: notify}, 'POST',	{
			'onSuccess' : function(ret) {
				var ansArea = $('.extension-point[extensionName="AnswerExtension"][aid="'+aid+'"] .ans-extension-area .answer-editor');
				$(".ans-content[aid='"+aid+"']").html(content);
				ansArea.slideToggle();
			},
			'onFailure' : function(ret) {
				sbj.notifyEvent("NotifyGlobal", "Sửa thất bại");
			}
		});
	},
	
	onShowAnswerEdit: function(eventData)	{
		var aid = eventData.aid;
		var ansArea = $('.extension-point[extensionName="AnswerExtension"][aid="'+aid+'"] .ans-extension-area .answer-editor');
		if (!ansArea.is(':visible'))	{
			var subject = SingletonFactory.getInstance(Subject);
			subject.notifyEvent('AnswerExtensionControlChanged', {value: ''});
		}
		ansArea.slideToggle();
	},

	onAnswerBuilt : function() {
		var loggedin = this.props.get('user.login');
		var obj = this;
		if (loggedin != 0)	{
			var curUID = this.props.get('user.id');
			$('.extension-point[extensionName="AnswerExtension"]').each(function()	{
				if ($(this).find('[flag="AnsEdit"]').length > 0)	{
					return;
				}
				var aid = $(this).attr('aid');
				var uid = $(this).attr('uid');
				if (curUID == uid)	{
					$(this).find('.ans-control .extension_place').append(tmpl('AnswerEditPlugin-Control', {uid: uid, aid: aid}));
					$(this).find('.ans-extension-area').append(tmpl('AnswerEditPlugin-Area', {uid: uid, aid: aid}));
					var curID = "OwnAnswerEditor-" + uid + "-" + aid;
					var content = $(".ans-content[aid='"+aid+"']").html();
					$("#"+curID).val(content);

					var sbj = SingletonFactory.getInstance(Subject);
					sbj.notifyEvent("TinyEditorInit", {id : curID,content : ""});
				}
			});
		}
	},
	
	onRejectChanges : function(eventData) {
		var curUid = eventData.uid;
		var curAid = eventData.aid;
		$("#extension-content-plhld-" + curAid + "-" + curUid).children("div[id='answer-editor-"+ curAid +"-"+curUid + "']").hide('fast');
	}
}).implement(PluginInterface).implement(AjaxInterface);

AnswerExtensionHiddenPlugin = Class.extend({
	init: function()	{
		this.name = "AnswerExtensionHiddenPlugin";
	},
	
	onAnswerExtensionControlChanged: function()	{
		$('.answer-extension-item').hide();
	}
}).implement(PluginInterface);
SearchMorePlugin = Class.extend({
	init: function()	{
		this.name = "SearchMorePlugin";
	},
	
	showSearchMoreButton: function()	{
		if ($('#effective-area .page_more').length > 0)
			$('#effective-area .page_more').show();
	},
	
	hideSearchMoreButton: function()	{
		if ($('#effective-area .page_more').length > 0)
			$('#effective-area .page_more').hide();
	},
	
	showNoMoreSearch: function()	{
		//if ($('#effective-area .no-more-search-result-placeholder').length > 0)	{
		//	$('#effective-area .no-more-search-result-placeholder').show();
		//}
	},
	
	hideNoMoreSearch: function()	{
		if ($('#effective-area .no-more-search-result-placeholder').length > 0)
			$('#effective-area .no-more-search-result-placeholder').hide();
	},
	
	onBeginSearching: function()	{
		this.showSearchMoreButton();
		this.hideNoMoreSearch();
	},
	
	onNoMoreResult: function()	{
		this.hideSearchMoreButton();
		this.showNoMoreSearch();
	},
	
	onHtmlUpdated: function()	{
		var obj = this;
		$('.extension-point[extensionName="PostResultList"]').each(function(index, value) {
			if ($(value).find('[flag="SearchMore"]').length > 0)	{
				return;
			}
			$(value).append(tmpl('SearchMorePluginTemplate', {}));
			obj.hideNoMoreSearch();
		});
	}
}).implement(PluginInterface);

QuestionTabPlugin = Class.extend({
	init: function()	{
		this.name = "QuestionTabPlugin";
		this.type = undefined;
	},
	
	onSearchResultChangeType: function(eventData)	{
		this.type = eventData.type;
		this.refreshType();
	},
	
	onSearchResultChangeScope: function(eventData)	{
		this.scope = eventData.scope;
		this.refreshScope();
	},
	
	refreshType: function()	{
		var type = this.type;
		$('a[type="Latest"]').removeClass('active');
		$('a[type="Top"]').removeClass('active');
		$('a[type="Open"]').removeClass('active');
		if (type == 'notification-filter' || type == undefined)	{
			$('a[type="Latest"]').addClass('active');
		} else if (type == 'question-best')	{
			$('a[type="Top"]').addClass('active');
		} else if (type == 'question-open')	{
			$('a[type="Open"]').addClass('active');
		}
	},
	
	refreshScope: function()	{
		var scope = this.scope;
		$('a[scope="limit"]').removeClass('active');
		$('a[scope="all"]').removeClass('active');
		if (scope == 'all')	{
			$('a[scope="all"]').addClass('active');
		} else {
			$('a[scope="limit"]').addClass('active');
		}
	},
	
	onHtmlUpdated: function()	{
		$('.extension-point[extensionName="SearchResultTitle"]').each(function(index, value) {
			if ($(value).find('[flag="QuestionTab"]').length > 0)	{
				return;
			}
			$(value).append(tmpl('QuestionTabTemplate', {}));
		});
		
		this.refreshScope();
		this.refreshType();
	},
	
	onEnd: function()	{
		$('#effective-area .tab-question').remove();
	}
}).implement(PluginInterface);
CleanStylePlugin = Class.extend({
	init: function()	{
		this.name = "CleanStylePlugin";
	},
	
	onCleanFont: function()	{
		$('.ans-content').find('[style]').each(function(index, value) {
			$(value).removeAttr('style');
		});
		
		$('.ans-content').find('font').each(function(index, value) {
			$(value).removeAttr('face');
			$(value).removeAttr('color');
		});
	}
}).implement(PluginInterface);
FocusDetectorPlugin = Class.extend({
	init: function()	{
		this.name = "FocusDetectorPlugin";
	},
	
	onAttachFocusDetection: function(eventData)	{
		var target = eventData.target;
		var defaultValue = eventData.defaultValue;
		$(target).attr('placeholder', defaultValue);
	}
}).implement(PluginInterface);
PaginationPlugin = Class.extend({
	init: function()	{
		this.name = "PaginationPlugin";
		this.pageLinks = Array();
		this.numPages = null;
		this.numDocs = null;
		this.rows = 10;
		this.curPage = 0;
		this.paginationPage = 0;
	},
	
	onFetchPaginationLink: function(eventData)	{
		this.numDocs = eventData.numDocs;
		this.rows = eventData.rows;
		this.curPage = eventData.curPage;
		this.request = eventData.request;
		$(eventData.placeholder).append(this.fetchPageLink());
	},
	
	onPaginationOnclick: function(pagination)	{
		this.request.setParam('pagination',  pagination);
		var sbj = SingletonFactory.getInstance(Subject);
		sbj.notifyEvent('RequestRoute', this.request);
	},
	
	fetchPageLink: function(){
		var result = $("<div></div>");
		var numPages = Math.ceil(this.numDocs / this.rows);
		if(numPages == 0){
			numPages = 1;
		}
		var curPage = parseInt(this.curPage); 
		var pageLinks = Array();
		if (curPage > numPages){
			curPage = numPages;
		}
		if (curPage <= 0){
			curPage = 1;
		}
		
		for(var x = 1; x <= numPages; x ++) {
			if (x == curPage) {
				var objParam = {};
				objParam.content = x;
				pageLinks[x-1] = tmpl("CommonPortlet-NavCurrent",objParam);
			} else {
				var objParam = {};
				objParam.content = x;
				objParam.page = x;
				pageLinks[x-1] = tmpl("Pagination-NavOther",objParam);
			}
		}
		
		if (curPage > 1 && curPage <= pageLinks.length){
			var objParam = {};
			objParam.page = curPage-1;
			objParam.content = "&#171 Trước&nbsp;";
			result.append(tmpl("Pagination-NavOther",objParam));
		}
		
		for (var key= curPage-11; key <= curPage+9; key++ ) {
			if (key<0) continue;
			if (key>= pageLinks.length) continue;
			if (key == curPage)
				result.append(pageLinks[key]);
			else
				result.append(pageLinks[key]);
		}		
		
		if(curPage < pageLinks.length){
			var objParam = {};
			objParam.page = curPage+1;
			objParam.content = "&nbsp;Sau&nbsp;&#187";
			result.append(tmpl("Pagination-NavOther",objParam));
		}
		return result;
	}
}).implement(PluginInterface);
ExpertisePlugin = Class.extend({
	init: function()	{
		this.name = "ExpertisePlugin";
	},
	
	onHtmlRendered: function(eventData)	{
		this.render();
	},
	
	onHtmlUpdated: function(eventData)	{
		this.render();
	},
	
	render: function(eventData)	{
		$('.extension-point[extensionName="ExpertiseTitle"]').each(function(index, value)	{
			if ($(value).find('div[flag="ExpertisePlugin"]').length > 0)
				return;
			var old = $(value).html();
			var eid = $(value).attr('extensionId');
			$(value).html("<a href='#!page/Topic/id/"+eid+"' onmouseover='generateEvent(&apos;ExpertiseTitleHover&apos;, event)'>"+old+"</a><div flag='ExpertisePlugin'></div>");
		});
		
		$('.extension-point[extensionName="InterestTitle"]').each(function(index, value)	{
			if ($(value).find('div[flag="ExpertisePlugin"]').length > 0)
				return;
			var old = $(value).html();
			var eid = $(value).attr('extensionId');
			$(value).html("<a href='#!page/Topic/id/"+eid+"' onmouseover='generateEvent(&apos;ExpertiseTitleHover&apos;, event)'>"+old+"</a><div flag='ExpertisePlugin'></div>");
		});
	}
}).implement(PluginInterface).implement(AjaxInterface);

TemplateDebugPlugin = Class.extend({
	init: function()	{
		this.rendered = false;
		this.name = "TemplateDebugPlugin";
	},
	
	onHtmlRendered: function(eventData)	{
		if (this.rendered)
			return;
		$.each($('.portlet-container'), function(index, value)	{
			$(value).append('<div>Portlet Container: '+$(value).attr('id')+'</div>');
		});
		this.rendered = true;
	}
}).implement(PluginInterface);

TextAreaAutoExpandPlugin = Class.extend({
	init: function()	{
		this.name = "TextAreaAutoExpandPlugin";
	},

	onExpandTextArea: function(eventData)	{
		var value = eventData.target;
		if ($(value).attr('flag') == 'TextAreaAutoExpand')
			return;
		var minHeight = eventData.min;
		var maxHeight = eventData.max;
		$(value).attr('flag', 'TextAreaAutoExpand');
		$(value).TextAreaExpander(minHeight, maxHeight);
	}
}).implement(PluginInterface);

FormatterPlugin = Class.extend({
	init: function()	{
		this.name = "FormatterPlugin";
	},
	
	onNeedFormatting: function(eventData)	{
		$('.extension-point[extensionName="Placeholder"]').each(function(index, value)	{
			if ($(value).attr('flag') == 'formatted')	{
				return;
			}
			
			//adjust depth
			var depth = $(value).attr('depth');
			if (depth == undefined) depth = 0;
			if (depth > 0) depth --;
			if (depth > 3) depth = 3;
//			$(value).attr('style', 'margin-left: '+(depth*115)+'px');
			var state = $(value).attr('state');
			var type = $(value).attr('type');
			var key = $($(value).find('.keyword')[0]).html();
			var v = $($(value).find('.content')[0]).html();
			
			var formatter = SingletonFactory.getInstance(FormatterFactory).getFormatter(type, state);
			if (formatter != undefined)	{
				formatter.format(key, v, value);
			}
			
			$(value).attr('flag', 'formatted');
		});
		
		$(".customDatePicker input").each(function(index, value)	{
			$(value).datepicker({dateFormat:"dd, M yy", 
				changeMonth: true,
				changeYear: true,
				yearRange:'-100:+10',
				showOn: "button",
				buttonImage: "static/images/cal.png",
				buttonImageOnly: true,
				buttonText: "Choose date",
				onSelect: function(dateText, inst) {$(value).attr("modified","true");}
			});
		});
	},
	
	onAddToken: function(eventData)	{
		if (eventData.keyCode == 13)	{
			var target = eventData.target;
			var partial = {};
			partial.content = $(target).val();
			partial.oid = "";
			//var container = $(target).siblings('.tokenContainer').append(tmpl('ListPartial-Edit', partial));
			$(target).val('');
		}
	},
	
	onDelToken: function(eventData)	{
		var target = eventData.target;
		$(target).parent().remove();
	},
	
	onAddEmailToken: function(eventData)	{
		if (eventData.keyCode == 13)	{
			var target = eventData.target;
			var provider = $(target).siblings('select').find('option:selected').html();
			var partial = {};
			partial.oid = "";
			partial.content = $(target).val()+'@'+provider;
			//var container = $(target).siblings('.tokenContainer').append(tmpl('ListPartial-Edit', partial));
			$(target).val('');
		}
	}
}).implement(PluginInterface);

FormatterFactory = Class.extend({
	getFormatter: function(type, state)	{
		var className = type+state+"Formatter";
		if (window[className] == undefined)	{
			//console.warn('Formatter '+type+'-'+state+' is not defined!');
			return undefined;
		} else {
			return new window[className	](state);
		}
	}
});

BaseFormatter = Class.extend({
	init: function()	{
		
	},
	
	format: function(key, value, placeholder)	{
		this.placeholder = placeholder;
		this.doFormat(key, value, placeholder);
	},
	
	doFormat: function(key, value, placeholder)	{
		$(placeholder).html(this.render(key, value));
	}
});

HeadingViewFormatter = BaseFormatter.extend({
	render: function(key, value)	{
		var obj = {};
		obj.keyword = key;
		obj.content = value;
		return tmpl('HeadingPlaceholder', obj);
	}
});

HeadingEditFormatter = HeadingViewFormatter.extend({});

HiddenViewFormatter = BaseFormatter.extend({
	render: function(key, value)	{
		return "";
	}
});

HiddenEditFormatter = HiddenViewFormatter.extend({});

NoneViewFormatter = BaseFormatter.extend({
	render: function(key, value)	{
		var obj = {};
		obj.keyword = key;
		return tmpl('NonePlaceholder', obj);
	}
});

NoneEditFormatter = NoneViewFormatter.extend({});

ListViewFormatter = BaseFormatter.extend({
	init: function()	{
		this.separator = ', ';
	},
	
	doFormat: function(key, value, placeholder)	{
		var keyword = $(placeholder).attr('name');
		var id = 'ListFormatter-'+keyword;
		var partial = {};
		partial.content = value;
		partial.oid = $(placeholder).parents('[rootname]:first').attr('oid');
		if (isNaN(partial.oid))	{
			partial.oid = "";
		}
		var fragment = this.buildFragment(partial);
		if (value == "" || $(placeholder).attr('mockup') == 'true')	{
			fragment = "";
		}
		
		//find the previous placeholder, because list is singleton
		if ($(placeholder).parents('.children_container:first').find('#'+id).length > 0)	{
			if (value == "" || $(placeholder).attr('mockup') == 'true')	{
				$(placeholder).remove();
				return;
			}
			$(placeholder).parents('.children_container:first').find('#'+id).find('.content').append(this.separator+fragment);
			$(placeholder).parent().parent().remove();
		} else {
			//not found, create new placeholder
			var obj = {};
			obj.id = id;
			obj.keyword = key;
			obj.content = fragment;
			var html = this.onRender(obj);
			$(placeholder).html(html);
		}
	},
	
	onRender: function(obj)	{
		return tmpl('ListPlaceholder', obj);
	},
	
	buildFragment: function(partial)	{
		return tmpl('ListPartial', partial);
	}
});

ListEditFormatter = ListViewFormatter.extend({
	init: function()	{
		this.separator = '';
	},
	
	onRender: function(obj)	{
		return tmpl('ListPlaceholder-Edit', obj);
	},
	
	buildFragment: function(partial)	{
		return tmpl('ListPartial-Edit', partial);
	}
});

NormalViewFormatter = BaseFormatter.extend({
	doFormat: function(key, value, placeholder)	{
		var obj = {};
		obj.keyword = key;
		obj.content = value;
		//find previous placeholder
		var keyword = $(placeholder).attr('name');
		if (this.checkDuplicate(keyword))	{
			obj.keyword = "";
		}
		obj.name = keyword;
		$(placeholder).html(this.onRender(obj));
	},
	
	checkDuplicate: function(keyword)	{
		return ($(this.placeholder).parent().parent().parent().find('.normal-formatter[name="'+keyword+'"]').length > 0);
	},
	
	onRender: function(obj)	{
		return tmpl('NormalPlaceholder', obj);
	}
});

BasicInfoViewFormatter = NormalViewFormatter.extend({
	onRender: function(obj)	{
		return tmpl('BasicInfoPlaceholder', obj);
	}
});

TitleViewFormatter = NormalViewFormatter.extend({
	onRender: function(obj)	{
		return tmpl('TitlePlaceholder', obj);
	}
});

NormalEditFormatter = NormalViewFormatter.extend({
	onRender: function(obj)	{
		return tmpl('NormalPlaceholder-Edit', obj);
	}
});

NormalLargeEditFormatter = NormalViewFormatter.extend({
	onRender: function(obj)	{
		return tmpl('NormalLargePlaceholder-Edit', obj);
	}
});

DateViewFormatter = NormalViewFormatter.extend({});

DateEditFormatter = NormalViewFormatter.extend({
	checkDuplicate: function(keyword)	{
		return ($(this.placeholder).parent().parent().parent().find('.date-formatter[name="'+keyword+'"]').length > 0);
	},
	
	onRender: function(obj)	{
		return tmpl('DatePlaceholder-Edit', obj);
	}
});

EmailViewFormatter = NormalViewFormatter.extend({});

EmailEditFormatter = ListEditFormatter.extend({
	init: function()	{
		this.separator = '';
	},
	
	onRender: function(obj)	{
		var params = $(this.placeholder).attr('params');
		var providers = params.split(',');
		var objProviders = {};
		objProviders.providers = providers;
		obj.select = tmpl('EmailProviders-Edit', objProviders);
		return tmpl('EmailPlaceholder-Edit', obj);
	}
});

EnumViewFormatter = NormalViewFormatter.extend({});

EnumEditFormatter = BaseFormatter.extend({
	doFormat: function(key, value, placeholder)	{
		var params = $(placeholder).attr('params');
		var choices = params.split(',');
		var str = "";
		for(var i in choices)	{
			var choice = choices[i];
			var checked = "";
			if (choice == value)	{
				checked = "checked";
			}
			var obj = {};
			obj.checked = checked;
			obj.choice = choice;
			obj.name = $(placeholder).attr('name');
			str += tmpl('EnumPartial-Edit', obj);
		}
		var enumObj = {};
		enumObj.content = str;
		enumObj.keyword = key;
		$(placeholder).html(tmpl('EnumPlaceholder-Edit', enumObj));
	}
});

UserControlBoxPlugin = Class.extend({
	init: function()	{
		this.name = "UserControlBoxPlugin";
	},
	
	onSystemPropertyChanged: function(eventData)	{
		if (eventData == 'user.login')	{
			this.setupUserBox();
		}
	},
	
	onUpdateUserStatus: function(eventData)	{
		this.onBegin();
	},
	
	onPageBegan: function()	{
		this.checkActiveMenu();
	},
	
	checkActiveMenu: function()	{
		var request = SingletonFactory.getInstance(Page).getRequest();
		var page = request.getName();
		$('#UserControlBoxPlugin a').each(function()	{
			var p = $(this).attr('page');
			if (p == page)	{
				$(this).addClass('active');
			} else {
				$(this).removeClass('active');
			}
		});
	},
	
	onBegin: function(eventData)	{
		var properties = SingletonFactory.getInstance(Application).getSystemProperties();
		var obj = this;
		this.onAjax('ajax', 'check-user-status', {}, 'GET', 
			{'onSuccess': function(ret)	{
				if (ret == 0)	{
					properties.set('user.login', 0, true);
					properties.set('user.id', -1, true);
				} else {
					properties.set('user.login', 1, true);
					properties.set('user.id', ret.id, true);
					properties.set('user.name', ret.name, true);
					properties.set('user.username', ret.username, true);
					properties.set('user.type', ret.type, true);
					properties.set('user.role', ret.role, true);
					properties.set('user.avatar', ret.avatar, true);
				}
				obj.setupUserBox();
			}});
	},

	setupUserBox: function()	{
		var systemProperties = SingletonFactory.getInstance(Application).getSystemProperties();
		var loggedIn = systemProperties.get('user.login');
		var obj = {};
		var page = SingletonFactory.getInstance(Page);
		var subject = SingletonFactory.getInstance(Subject);
		if (loggedIn == true)	{
			subject.notifyEvent('FetchLiveNotification');
			obj.login = true;
			obj.name = systemProperties.get('user.name');
		} else {
			obj.login = false;
			if (page.pagename == 'Home')	{
				subject.notifyEvent('RequestRoute', new Request('Introduce'));
			}
		}
		if ($('#UserControlBoxPlugin').length <= 0)	{
			$('div.extension-point[extensionName="TopRight"]').append(tmpl('UserControlBoxPluginContainer', {}));
		}
		var type = systemProperties.get('user.type');
		if (type == 'person'){
			obj.userPage = 'User/id/'+systemProperties.get('user.id');;
		} else if (type == 'partner'){
			obj.userPage = 'PartnerProfile/id/'+systemProperties.get('user.id');
		}
		 
		$('#UserControlBoxPlugin').html(tmpl('UserControlBoxPluginTmpl', obj));
//		$("li.cutdi").blur(function () {
//	         $('#navAccount').addClass('_hidden');
//	    });
		this.checkActiveMenu();
	},
	
	onToggleAccountNav: function()	{
		if($('#navAccount').is("._hidden")) $('#navAccount').removeClass("_hidden");
		else $('#navAccount').addClass("_hidden");
	},
	
	onEnd: function()	{
		if ($('#UserControlBoxPlugin').length > 0)
			$('#UserControlBoxPlugin').remove();
	}
}).implement(PluginInterface).implement(AjaxInterface);

LiveNotificationPlugin = Class.extend({
	init: function()	{
		this.name = "LiveNotificationPlugin";
		this.fullFetched = false;
	},
	
	onBegin: function()	{
		this.startInterval(300000, this.fetch);
	},
	
	onFetchLiveNotification: function()	{
		this.fetch();
	},
	
	onFetchFullNotifications: function() {
		if (this.fullFetched)
			return;
		this.fullFetched = true;
		this.onAjax('user-ajax', 'get-full-notification', {}, 'GET', {
			onSuccess: function(ret)	{
				var notifs = Array();
				for(var i=0;i<ret.length;i++)	{
					var link = eval("("+ret[i].link+")");
					var href=Array();
					for(var j in link)	{
						var param = j;
						if (param == 'type')
							param = 'page';
						href.push(param+"/"+link[j]);
					}
					ret[i].content = tmpl('NotificationItem-'+ret[i].type, ret[i]);
					ret[i].link = "#!"+href.join("/");
					notifs.push(ret[i]);
				}
				$('#NotificationDropdown').html(tmpl('NotificationList', {notifs: notifs}));
				$('#NotificationNumber').html('0');
				$('#NotificationNumber').css('background-color', '#AAA');
			}
		});
	},
	
	fetch: function()	{
		var loggedin = SingletonFactory.getInstance(Application).getSystemProperties().get('user.login');
		if (loggedin == 1)	{
			this.onAjax('user-ajax', 'get-live-notification', {}, 'GET', {
				'onSuccess': function(ret)	{
					$('#NotificationNumber').html(ret);
					if (ret == 0)	{
						$('#NotificationNumber').css('background-color', '#AAA');
					}
				}
			});
		}
	}
}).implement(PluginInterface).implement(AjaxInterface).implement(IntervalTimerInterface);

UserLogoutPlugin = Class.extend({
	init: function()	{
		this.name = "UserLogoutPlugin";
	},
	
	onPageBegan: function()	{
		this.onAjax('ajax', 'logout', {}, 'POST', {
			'onSuccess': function(ret)	{
				var systemProperties = SingletonFactory.getInstance(Application).getSystemProperties();
				systemProperties.set('user.login', 0, true);
				systemProperties.set('user.id', undefined, true);
				var request = new Request("Introduce");
				var subject = SingletonFactory.getInstance(Subject);
				subject.notifyEvent("RequestRoute", request);
			}
		});
	}
}).implement(PluginInterface).implement(AjaxInterface);
ExpertiseEditorPlugin = Class.extend({
	init: function()	{
		this.name = "ExpertiseEditorPlugin";
	},
	
	onSubmitExpertiseForward: function(eventData)	{
		var namespace = eventData.namespace;
		
		var expToSent = Array();
		var expcontainer = $('#'+namespace+'-ListExpertise .tokenContainer');
		$(expcontainer).find('label.lblToken').each(function(index, value)	{
			var id = $(value).attr('eid');
			expToSent.push(id);
		});
		
		var callback = eventData.callback;
		if (expToSent.length == 0)	{
			callback();
			return;
		}
		expToSent = expToSent.join(',');
		
		var subject = SingletonFactory.getInstance(Subject);
		this.onAjax('user-ajax', 'add-expertise', {'experts': expToSent}, 'POST', 
			{'onSuccess': function(ret)	{
				callback();
				$(expcontainer).html('');
				subject.notifyEvent('ExpertiseChanged');
			}
		});
	},
	
	onRenderExpertiseEditor: function(eventData)	{
		this.placeholder = eventData.placeholder;
		var namespace = eventData.namespace;
		$(this.placeholder).html(tmpl('ExpertiseSubplaceholder', {}));
		var expertiseMsg = 'Kinh nghiệm';
		var guideExpertiseMsg = 'Bạn nên nhập đầy đủ kinh nghiệm của mình để người khác có thể dễ dàng kết nối đến bạn hơn';
		$(this.placeholder).find('#ProfileExpertise').html(tmpl('ListContainer', {'id':'ListExpertise', 'name': 'expertise', 'keyword':expertiseMsg, 'namespace':namespace,'guideMsg':guideExpertiseMsg}));
		
		var addExpertiseInput = $(this.placeholder).find('[container="ListExpertise"] input.ui-autocomplete-input');
		
		//setup autocomplete
		var eventData = {};
		eventData.focusCallback = "RegisterAddExpertiseFocus";
		eventData.selectCallback = "RegisterAddExpertiseSelect";
		eventData.autocompleteObject = addExpertiseInput;
		var solrRoot = SingletonFactory.getInstance(Application).getSystemProperties().get('host.solr');
		eventData.autocompleteSource = solrRoot+"/autocomplete/catch";
		var subject = SingletonFactory.getInstance(Subject);
		subject.notifyEvent('NeedAutocomplete', eventData);
	},
	
	onRegisterAddExpertiseFocus: function(eventData)	{
		var ui = eventData.ui;
		var addExpertiseInput = $(this.placeholder).find('[container="ListExpertise"] input.ui-autocomplete-input');
		$(addExpertiseInput).val(ui.item.label);
	},
	
	onRegisterAddExpertiseSelect: function(eventData)	{
		var ui = eventData.ui;
		var label = ui.item.label;
		var tmp = null;
		try {
			tmp = $("a[catch='"+escape(label)+"']");	
		} catch (e) {
			// TODO: handle exception
		}
		var value = tmp.attr("catch_id");
		var addExpertiseContainer = $(this.placeholder).find('[container="ListExpertise"] div.tokenContainer');
		var addExpertiseInput = $(this.placeholder).find('[container="ListExpertise"] input.ui-autocomplete-input');
		$(addExpertiseInput).val('');
		$(addExpertiseContainer).append(tmpl('TokenPartial', {'label':label, 'value':value}));
	}
}).implement(PluginInterface).implement(AjaxInterface);

InterestEditorPlugin = Class.extend({
	init: function()	{
		this.name = "InterestEditorPlugin";
	},
	
	onSubmitInterestForward: function(eventData)	{
		var namespace = eventData.namespace;
		
		var intToSent = Array();
		var intcontainer = $('#'+namespace+'-ListInterestedArea .tokenContainer');
		$(intcontainer).find('label.lblToken').each(function(index, value)	{
			var id = $(value).attr('eid');
			intToSent.push(id);
		});
		var callback = eventData.callback;
		if (intToSent.length == 0)	{
			callback();
			return;
		}
		intToSent = intToSent.join(',');
		
		var subject = SingletonFactory.getInstance(Subject);
		this.onAjax('user-ajax', 'add-expertise', {'interests': intToSent}, 'POST', 
			{'onSuccess': function(ret)	{
				callback();
				$(intcontainer).html('');
				subject.notifyEvent('InterestedAreaChanged');
			}
		});
	},
	
	onRenderInterestEditor: function(eventData)	{
		this.placeholder = eventData.placeholder;
		var namespace = eventData.namespace;
		$(this.placeholder).html(tmpl('ExpertiseSubplaceholder', {}));
		var followMsg = 'Lĩnh vực quan tâm';
		var guideFollowMsg = 'Bạn nên nhập lĩnh vực quan tâm để chúng tôi có thể dễ dàng gợi ý cho bạn những câu hỏi mà bạn quan tâm';
		$(this.placeholder).find('#ProfileFollow').html(tmpl('ListContainer', {'id':'ListInterestedArea','name': 'interested-area', 'keyword':followMsg, 'namespace':namespace,'guideMsg':guideFollowMsg}));
		
		var addInterestInput = $(this.placeholder).find('[container="ListInterestedArea"] input.ui-autocomplete-input');
		
		//setup autocomplete
		var eventData = {};
		eventData.focusCallback = "RegisterAddInterestFocus";
		eventData.selectCallback = "RegisterAddInterestSelect";
		eventData.autocompleteObject = addInterestInput;
		var solrRoot = SingletonFactory.getInstance(Application).getSystemProperties().get('host.solr');
		eventData.autocompleteSource = solrRoot+"/autocomplete/catch";
		var subject = SingletonFactory.getInstance(Subject);
		subject.notifyEvent('NeedAutocomplete', eventData);
	},
	
	onRegisterAddInterestFocus: function(eventData)	{
		var ui = eventData.ui;
		var addInterestInput = $(this.placeholder).find('[container="ListInterestedArea"] input.ui-autocomplete-input');
		$(addInterestInput).val(ui.item.label);
	},
	
	onRegisterAddInterestSelect: function(eventData)	{
		var ui = eventData.ui;
		var label = ui.item.label;
		var value = ui.item.id;
		var addInterestContainer = $(this.placeholder).find('[container="ListInterestedArea"] div.tokenContainer');
		//var addInterestInput = $(this.placeholder).find('[container="ListInterestedArea"] input.ui-autocomplete-input');
		$(addInterestContainer).append(tmpl('TokenPartial', {'label':label, 'value':value}));
	}	
}).implement(PluginInterface).implement(AjaxInterface);

ExpertiseDeletePlugin = Class.extend({
	init: function()	{
		this.name = "ExpertiseDeletePlugin";
	},
	
	onHtmlUpdated: function(eventData)	{
		$('#effective-area .extension-point[extensionName="ExpertisePartial"]').each(function(index, value)	{
			if ($(value).find('[flag="ExpertiseDelete"]').length > 0)
				return;
			$(value).append('<span flag="ExpertiseDelete"></span>');
			var obj = {};
			obj.id = $(value).attr('extensionId');
			$(value).append(tmpl('ExpertiseDelete', obj));
		});
	},
	
	onExpertiseDeleteButtonClick: function(eventData)	{
		var target = eventData.target;
		var id = $(target).attr('eid');
		this.onAjax('user-ajax', 'remove-single-expertise', {'id':id}, 'POST', 
			{'onSuccess': function(ret)	{
				$(target).parents(".uiListItem:first").remove();
			},
			'onFailure': function(){
				$.facebox('Hiện thời hệ thống không thể xóa mục này. Bạn vui lòng thử lại sau');
			}
		});
	}
}).implement(PluginInterface).implement(AjaxInterface);

ExpertRankPlugin = Class.extend({
	init: function()	{
		this.name = "ExpertRankPlugin";
		this.getInfo();
	},
	
	getInfo: function(){
		var _this = this;
		var request = SingletonFactory.getInstance(Page).getRequest();
		var profileid = request.getParam('id');
		_this.onAjax('ajax','get-expert-rank-user',{'uid':profileid},'GET',{
			'onSuccess':function(ret){
				if(ret[0] != undefined){
					SingletonFactory.getInstance(Application).getSystemProperties().set("memcached.expertise", ret[0]);
				}
			}
		},true,300000);
	},
	
	render: function()	{
		$('#effective-area .extension-point[extensionName="expertisePartialLeft"]').each(function(index, value)	{
			if ($(value).find('.flag[flagName="expertiseRank"]').length > 0)
				return;
			var obj = {};
			obj.id = $(value).attr('extensionId');
			
			// solr query
			if(SingletonFactory.getInstance(Application).getSystemProperties().get("memcached.expertise") != undefined){
				var ret = SingletonFactory.getInstance(Application).getSystemProperties().get("memcached.expertise");
				if(ret['expert_rank_position_' + obj.id] != undefined){
					obj.rank = ret['expert_rank_position_' + obj.id];
					obj.expertRank = ret['expert_rank_percentage_' + obj.id];
					var objParam = {};
					objParam.er = obj.expertRank;
					objParam.total = 1000;
					obj.tips = tmpl("ExpertiseRankDescription",objParam);
					$(value).append($('<span class="flag" flagName="expertiseRank"></span>'));
					$(value).append("&nbsp;");
					$(value).append(tmpl('ExpertiseRank', obj));
				} else {
					obj.expertRank = 0;
				}
			} else {
				
			}
			
			
//			_this.onAjax('ajax', 'get-expert-rank-specific-user', {'uid':profileid, 'cid':obj.id}, 'GET', {
//				'onSuccess': function(ret)	{
//					if ($(value).find('.flag[flagName="expertiseRank"]').length > 0)
//						return;
//					
//					if(ret[0] != undefined && ret[0].expertRank != undefined){
//						obj.rank = ret[0].rank;
//						obj.expertRank = Math.round(10000 * ret[0].expertRank)/100;
//					} else {
//						obj.rank = "0";
//					}
//					var objParam = {};
//					objParam.er = obj.expertRank;
//					objParam.total = 1000;
//					obj.tips = tmpl("ExpertiseRankDescription",objParam);
//					$(value).append($('<span class="flag" flagName="expertiseRank"></span>'));
//					$(value).append("&nbsp;");
//					$(value).append(tmpl('ExpertiseRank', obj));
//				}
//			}, true, 300000);
		});
	},
	
	onReloadPlugin: function(eventData)	{
		var _this = this;
		var request = SingletonFactory.getInstance(Page).getRequest();
		var profileid = request.getParam('id');
		_this.onAjax('ajax','get-expert-rank-user',{'uid':profileid},'GET',{
			'onSuccess':function(ret){
				if(ret[0] != undefined){
					SingletonFactory.getInstance(Application).getSystemProperties().set("memcached.expertise", ret[0]);
				}
				this.render();
			}
		},true,300000);
	},
	
	onHtmlUpdated: function(eventData)	{
		this.render();
	}
}).implement(PluginInterface).implement(AjaxInterface);

ExpertiseEditPlugin = Class.extend({
	init: function()	{
		this.name = "ExpertiseEditPlugin";
	},
	
	onExpertiseEditableBlur: function(eventData)	{
		var target = eventData.target;
		var id = $(target).attr('eid');
		var oldhtml = $(target).attr('oldhtml');
		var explanation = $(target).val();
		if (explanation == undefined || explanation.trim() == '')	{
			explanation = oldhtml;
		}
		if (oldhtml != explanation)	{
			this.onAjax('user-ajax', 'update-single-expertise', {'id': id, 'explanation': explanation}, 'POST', {});
		}
		$(target).parent().html(explanation);
		$(target).removeClass('ui-editable-edit');
	},
	
	onExpertiseEditClick: function(event)	{
		var target = $(event.target);
		var container = $(target).parent().siblings('.topic-info');
		var oldhtml = $(container).html().trim();
		var id = $(target).attr('eid');
		$(container).addClass('ui-editable-edit');
		$(container).html('<input eid='+id+' oldhtml="'+oldhtml+'" onblur="generateEvent(&apos;ExpertiseEditableBlur&apos;, event)" type="text" class="text" value="'+oldhtml+'">');
		$(container).find('input').focus();
	},
	
	onHtmlUpdated: function(eventData)	{
		$('.extension-point[extensionName="ExpertiseExplanation"]').each(function(index, value)	{
			if ($(value).find('[flag="ExpertiseExplanationEdit"]').length > 0)
				return;
			$(value).append('<span flag="ExpertiseExplanationEdit"></span>');
			var obj = {};
			obj.id = $(value).attr('extensionId');
			
			$(value).append(tmpl('ExpertiseEdit', obj));
//			$(value).addClass('editableLabel');
//			$(value).bind('click', function(event)	{
//				var target = event.target;
//				var oldhtml = $(target).html().trim();
//				var id = $(target).attr('eid');
//				$(target).addClass('ui-editable-edit');
//				$(target).html('<input eid='+id+' oldhtml="'+oldhtml+'" onblur="generateEvent(&apos;ExpertiseEditableBlur&apos;, event)" type="text" value="'+oldhtml+'">');
//				$(target).find('input').focus();
//			});
		});
	}
}).implement(PluginInterface).implement(AjaxInterface);

InterestDeletePlugin = Class.extend({
	init: function()	{
		this.name = "InterestDeletePlugin";
	},
	
	onHtmlUpdated: function(eventData)	{
		$('#effective-area .extension-point[extensionName="InterestPartial"]').each(function(index, value)	{
			if ($(value).find('[flag="InterestDelete"]').length > 0)
				return;
			$(value).append('<span flag="InterestDelete"></span>');
			var obj = {};
			obj.id = $(value).attr('extensionId');
			$(value).append(tmpl('InterestDelete', obj));
		});
	},
	
	onInterestDeleteButtonClick: function(eventData)	{
		var target = eventData.target;
		var id = $(target).attr('eid');
		this.onAjax('user-ajax', 'remove-single-interest',
			{'id': id}, 'POST', {
				onSuccess: function(ret)	{
					$(target).parent().parent().remove();
				}
			});
	}
}).implement(PluginInterface).implement(AjaxInterface);
/**
 * 
 */
UserCheckLoginPlugin = Class.extend({
	init: function()	{
		this.name = "UserCheckLoginPlugin";
	},
	
	onPageBegan: function()	{
		var properties = SingletonFactory.getInstance(Application).getSystemProperties();
		var loggedIn = properties.get('user.login', undefined);
		var root = properties.get('host.root');
		var subject = SingletonFactory.getInstance(Subject);
		if (loggedIn == undefined)	{
			//query to server
			this.onAjax('ajax', 'check-user-status', {'profile-id':this.profile_id}, 'POST', 
					{'onSuccess': function(ret)	{
						if (ret == 0)	{
							properties.set('user.login', 0, true);
							var request = new Request('Login', undefined, null);
							subject.notifyEvent("RequestRoute", request);
						} else {
							properties.set('user.login', 1, true);
							properties.set('user.id', ret.userid, true);
						}
					}});
		} else if (loggedIn == false)	{
			var request = new Request('Login', undefined, null);
			subject.notifyEvent("RequestRoute", request);
		}
	}
}).implement(PluginInterface);

LoginSuccessRedirectPlugin = Class.extend({
	init: function()	{
		this.name = "LoginSuccessRedirectPlugin";
	},
	
	onLoginSuccess: function()	{
		var app = SingletonFactory.getInstance(Application);
		//FIXME: What is this? I don't remember :(
		var history = app.getSystemProperties().get("request.callback");
		var request = history != undefined ? history : new Request('Home', undefined, null);
		app.getSystemProperties().set("request.callback", undefined);
		var subject = new SingletonFactory.getInstance(Subject);
		subject.notifyEvent('RequestRoute', request);
	}
}).implement(PluginInterface);
ProfileEditTabPlugin = Class.extend({
	init: function()	{
		this.name = "ProfileEditTabPlugin";
	},

	onRenderProfileEditTab: function(eventData)	{
		var placeholder = eventData.placeholder;
		var tabs = eventData.tabs;
		var obj = {};
		obj.tabs = tabs;
		var tabMeta = tmpl('TabsMeta', obj);
		$(placeholder).prepend(tabMeta);
		$(placeholder).tabs();
	}
}).implement(PluginInterface);
/**
 * 
 */

ProfileImageCheckPlugin = Class.extend({
	init: function()	{
		this.name = "ProfileImageCheckPlugin";
	},
	
	onHtmlRendered: function(eventData)	{
		this.render();
	},
	
	onHtmlUpdated: function(eventData)	{
		this.render();
	},
	
	onFixBrokenImage: function(eventData){
		this.render();
	},
	
	render: function(eventData)	{
			$("img.bkp_pic_profile").error(
				function() {
					$(this).attr("src", "resource/images/unknown.png");
				});
	},
	
	onRequestProfileImageCheck: function(eventData){
		var zone = eventData.zone;
		$(zone).find("img.bkp_pic_profile").error(
			function() {
				$(this).attr("src", "resource/images/unknown.png");
		});
	}
}).implement(PluginInterface);

/**
 * 
 */

NavigateRoutePlugin = Class.extend({
	init: function()	{
		this.name = "NavigateRoute";
	},
	
	onGoToPrevious: function(eventData)	{
		history.go(-2);
	},
	
	onGoToHome: function(eventData)	{
		var subject = SingletonFactory.getInstance(Subject);
		var request = new Request("Home",undefined, null); 
		subject.notifyEvent('RequestRoute', request);
	},
	
	onGoToPage: function(eventData)	{
		var subject = SingletonFactory.getInstance(Subject);
		var request ;
		if(eventData.page == undefined){
			//console.error("Error ! No page to go to");
		}else{
			var pagename = eventData.page;
			var params = eventData.params;
			request = new Request(pagename, undefined, params);
			subject.notifyEvent('RequestRoute', request);
		}
	}
}).implement(PluginInterface);

NavigatorPlugin = Class.extend({
	init: function() {
		this.name = "NavigatorUI";
		this.pageLinks = Array();
		this.numPages = null;
		this.numDocs = null;
		this.rows = 10;
		this.curPage = 0;
		this.searchPage = 0;
		this.dataLength = 0;
		this.searchController = "";
	},
	
	onFetchSearchResultNumber: function(eventData){
		eventData.numDocs = eventData.numDocs || 0;
		var template = tmpl("SearchResultPortlet-SearchResultNumber",eventData);
		$('.extension-point[extensionName="SearchResultTitle"]').each(function(index, value)	{
			$(value).append(template);
		});
	},
	
	onFetchNavigationLink: function(eventData){
		this.numDocs = eventData.numDocs;
		this.rows = eventData.rows;
		this.searchPage = eventData.searchPage;
		this.dataLength = eventData.dataLength;
		this.query = eventData.query;
		this.core = eventData.core;
		this.searchController = eventData.searchController;
		
		var currentPlugin = this;
		$('.extension-point[extensionName="NavigatorUI"]').each(function(index, value)	{
			$(value).append(currentPlugin.fetchPageLink());
		});
	},
	
	fetchPageLink: function(){
		var result = $("<div></div>");
		if(this.dataLength == 0){
			return result;
		}
		var numPages = Math.ceil(this.numDocs / this.rows);
		if(numPages == 0){
			numPages = 1;
		}
		var curPage = parseInt(this.searchPage); 
		var pageLinks = Array();
		if (curPage > numPages){
			curPage = numPages;
		}
		if (curPage <= 0){
			curPage = 1;
		}
		
		for(var x = 1; x <= numPages; x ++) {
			if (x == curPage) {
				var objParam = {};
				objParam.content = x;
				pageLinks[x-1] = tmpl("CommonPortlet-NavCurrent",objParam);
			} else {
				var objParam = {};
				objParam.query = this.query;
				objParam.core = this.core;
				objParam.searchPage = x;
				objParam.content = x;
				objParam.rows = this.rows;
				objParam.searchController = this.searchController;//"SearchResultDynamic";
				pageLinks[x-1] = tmpl("CommonPortlet-NavOther",objParam);
			}
		}
		
		if (curPage > 1 && curPage <= pageLinks.length){
			var objParam = {};
			objParam.query = this.query;
			objParam.core = this.core;
			objParam.searchPage = curPage-1;
			objParam.content = "&#171 Trước&nbsp;";
			objParam.rows = this.rows;
			objParam.searchController = this.searchController;//"SearchResultDynamic"
			result.append(tmpl("CommonPortlet-NavOther",objParam));
		}
		
		
		for (var key= curPage-11; key <= curPage+9; key++ ) {
			if (key<0) continue;
			if (key>= pageLinks.length) continue;
			if (key == curPage)
				result.append(pageLinks[key]);
			else
				result.append(pageLinks[key]);
		}		
		
		if(curPage < pageLinks.length){
			var objParam = {};
			objParam.query = this.query;
			objParam.core = this.core;
			objParam.searchPage = curPage+1;
			objParam.content = "&nbsp;Sau&nbsp;&#187";
			objParam.rows = this.rows;
			objParam.searchController = this.searchController;;//"SearchResultDynamic";
			result.append(tmpl("CommonPortlet-NavOther",objParam));
		}
		return result;
	}
}).implement(PluginInterface);

/**
 * 
 */

BKPTextEditorPlugin = Class.extend({
	init : function() {
		this.name = "BKPTextEditorPlugin";
		this.mceNeeded = false;
		this.i = 0;
	},
	
	onTinyEditorInit: function(eventData){
		var id = eventData.id;
		var mem = SingletonFactory.getInstance(Application).getSystemProperties().get("memcached.tinyeditor");
		/*if(mem == undefined){
			mem = Array();
		}
		if(mem[id] != undefined){
			return;
		}*/
		mem = Array();
		var instance = new TINY.editor.edit('editor' ,{
		    id:id,
		    height:'200px',
		    width:'100%',
		    cssclass:'te',
		    controlclass:'tecontrol',
		    rowclass:'teheader',
		    dividerclass:'tedivider',
		    controls:['bold','italic','underline','|',
		              'orderedlist','unorderedlist','|','outdent','indent','|','leftalign',
		              'centeralign','rightalign','blockjustify','|',,'insertcode','|','redo','undo','n',
		              'link','unlink','|','image','|','unformat'],
		    footer:true,
		    fonts:['Verdana','Arial','Georgia','Trebuchet MS'],
		    xhtml:true,
		    cssfile:'static/js/thirdparty/tinyeditor/style.css',
		    bodyid:'editor',
		    footerclass:'tefooter',
		    toggle:{text:'source',activetext:'wysiwyg',cssclass:'toggle'},
		    resize:{cssclass:'resize'}
		});
		mem[id]= instance;
		SingletonFactory.getInstance(Application).getSystemProperties().set("memcached.tinyeditor",mem);
	},
	
	onEnd: function(){
		SingletonFactory.getInstance(Application).getSystemProperties().set("memcached.tinyeditor",undefined);
	}
}).implement(PluginInterface);

/**
 * 
 */

PostPlugin = Class.extend({
	init : function() {
		this.name = "PostPlugin";
		this.app = SingletonFactory.getInstance(Application);
		this.root = this.app.getSystemProperties().get("host.root");
//		this.topics = this.app.getSystemProperties().get(
//				"memcached.topics");
//		this.contexts = this.app.getSystemProperties().get(
//				"memcached.contexts");
//		this.contextsDescription = null;
//
//		this.addedContexts = null;
//		this.contextMap = Array();
//		this.addedContextsNumber = 0;
//		this.addedTopics = null;
//		this.topicMap = Array();
//		this.topicAvaiContextCommit = Array();
//		this.topicNewContextCommit = Array();
	},

	onVoteUpQuestion : function(eventData) {
		this.checkUserLogin(eventData, "VoteUpQuestion");
	},

	voteUpQuestion : function(eventData) {
		this.onAjax('question', 'update-vote', {qid: eventData.id, type: 1}, 'POST', {
			'onSuccess': function(ret) {
				var up = parseInt($("#AnswerPortlet-QVote").html().substr(1));
				up += 1;
				$("#AnswerPortlet-QVote").html("+"+up);
				return;
			}
		});
	},

	onVoteDownQuestion : function(eventData) {
		this.checkUserLogin(eventData, "VoteDownQuestion");
	},

	voteDownQuestion : function(eventData) {
		var url = this.prepareQuestionUrl(eventData, 0);
		$.get(url, {}, function(ret) {
			ret = $.parseJSON(ret);
			ret = ret.result;
			if (ret == "success") {
				var up = parseInt($(".bkp_q_vote_down").html());
				up += 1;
				$(".bkp_q_vote_down").html(up);
				return;
			}
		});
	},

	// login
	onVoteAnswerIncrease : function(eventData) {
		this.checkUserLogin(eventData, "VoteAnswerIncrease");
	},

	voteAnswerIncrease : function(eventData) {
		this.onAjax('answer', 'update-vote', {aid: eventData.id, type: 1}, 'POST', {
			'onSuccess': function(ret) {
				var aid = eventData.id;
				var current = parseInt($("#AnswerPortlet-AVote-" + aid).html().substr(1));
				current += 1;
				$("#AnswerPortlet-AVote-" + aid).html("+"+current);
				return;
			}
		});
	},

	// login
	onVoteAnswerDecrease : function(eventData) {
		this.checkUserLogin(eventData, "VoteAnswerDecrease");
	},

	voteAnswerDecrease : function(eventData) {
		var url = this.prepareUrl(eventData, 0);
		$.get(url, {}, function(ret) {
			ret = $.parseJSON(ret);
			ret = ret.result;
			if (ret == "success") {
				var aid = eventData.aid;
				var current = parseInt($(
						"#answer-" + aid + "-voteNum")
						.children().html());
				current -= 1;
				$("#answer-" + aid + "-voteNum").children()
						.html(current);
				// $("#vote-down-" + aid).attr("onclick",
				// "return false");
				return;
			}
		});
	},

//	onToggleDownEditTopic : function(eventData) {
//		var id = eventData.id;
//		$("#" + id).slideToggle('fast');
//		$("#bkp-topic-search-new").val("");
//		this.buildTopics(SingletonFactory.getInstance(
//				Application).getSystemProperties().get(
//				"memcached.topics"));
//	},
//
//	onToggleUpEditTopic : function(eventData) {
//		var id = eventData.id;
//		// $("#" + id).children("input[type=text]").val("");
//		$("#" + id).slideToggle('fast');
//	},
//
//	// login
//	onTopicAdded : function(eventData) {
//		this.checkUserLogin(eventData, "TopicAdded");
//	},
//
//	topicAdded : function(eventData) {
//		var id = eventData.id;
//		// var value = $("#" +
//		// id).children("input[type=text]").val().trim();
//		// if(value == ""){
//		// return;
//		// }
//		var params = SingletonFactory.getInstance(Page)
//				.getRequest().getParams();
//		var questionID = params["qid"];
//		var selected = $("#" + id + "  option:selected");
//		for ( var i = 0; i < selected.length; i++) {
//			var value = $(selected[i]).val();
//			var text = $(selected[i]).text();
//
//			// TODO: đưa value lên server
//			// đưa value vào trong list
//			// Nếu trong list có rồi thì thoi
//			var topicAdded = this.app.getSystemProperties()
//					.get("memcached.addedTopics");
//			if (topicAdded[value] != undefined) {
//				return;
//			}
//
//			var objParam = {};
//			objParam.tid = generateId("tt");
//			objParam.content = text;
//			objParam.cid = value;
//			objParam.uid = this.app.getSystemProperties().get("user.id");
//			var newTp = tmpl("AnswerPortlet-Topic", objParam);
//			
//			$("#" + id).parent().parent().siblings(
//					".bkp_question_topics").append(newTp);
//
//			// set back to memcached
//			topicAdded[value] = objParam.tid;
//			var sysProp = this.app.getSystemProperties();
//			sysProp.set("memcached.addedTopics", topicAdded);
//
//			// dump to server
//			var curUrl = this.root
//					+ "question/add-catchword/qid/"
//					+ questionID + "/cid/" + value;
//			var sbj = SingletonFactory.getInstance(Subject);
//			$.ajax({
//				url : curUrl,
//				data : {},
//				success : function(ret) {
//					sbj.notifyEvent("NotifyGlobal",
//							"Thêm thành công");
//				},
//				error : function() {
//					sbj.notifyEvent("NotifyGlobal",
//							"Thêm thất bại");
//				}
//			});
//		}
//	},
//
//	onTopicDeleted : function(eventData) {
//		this.checkUserLogin(eventData, "TopicDeleted");
//	},
//
//	topicDeleted : function(eventData) {
//		var id = eventData.id;
//		var params = SingletonFactory.getInstance(Page)
//				.getRequest().getParams();
//		var questionID = params["qid"];
//		var value = $("#" + id).attr("cid")
//		var text = $("#" + id + " label").text();
//
//		var topicAdded = this.app.getSystemProperties().get(
//				"memcached.addedTopics");
//		topicAdded[value] = undefined;
//		var sysProp = this.app.getSystemProperties();
//		sysProp.set("memcached.addedTopics", topicAdded);
//
//		$("#" + id).remove();
//		// dump to server
//		var curUrl = this.root
//				+ "question/remove-catchword/qid/" + questionID
//				+ "/cid/" + value;
//		var sbj = SingletonFactory.getInstance(Subject);
//		$
//				.ajax({
//					url : curUrl,
//					data : {},
//					success : function(ret) {
//						sbj.notifyEvent("NotifyGlobal",
//								"Xóa thành công");
//					},
//					error : function() {
//						sbj.notifyEvent("NotifyGlobal",
//								"Xóa thất bại");
//					}
//				});
//	},
//
//	onTopicChanged : function(eventData) {
//		var id = eventData.id;
//		var pid = eventData.pid;
//		var value = $("#" + id).val().trim().replace("  ", " ")
//				.toLowerCase();
//		var e = eventData.e;
//		var topics = SingletonFactory.getInstance(Application)
//				.getSystemProperties().get("memcached.topics");
//		var arr = Array();
//		var newTopics = null;
//		var isEqual = false;
//		for ( var key in topics) {
//			var curObj = topics[key];
//			var content = curObj['catchWord'].toLowerCase();
//			var match = new RegExp(value);
//			if (content == value) {
//				isEqual = true;
//			}
//			if (match.test(content)) {
//				arr.push(curObj);
//			}
//		}
//
//		newTopics = this.buildTopics(arr);
//		if (newTopics != null) {
//			$("#" + pid).empty().append(newTopics.children());
//		}
//	},
//
//	buildTopics : function(arr) {
//		var result = $("<div><div></div></div>");
//		for ( var key in arr) {
//			var curObj = arr[key];
//			var newTp = $("<option value='" + curObj['id']
//					+ "'>" + curObj['catchWord'] + "</option>");
//			result.children().append(newTp);
//		}
//		return result.children();
//	},
//
//	onMoreContent : function(eventData) {
//		var uiid = eventData.uiid;
//		var parentID = eventData.pid;
//		var templateID = eventData.tid;
//		var templateFields = eventData.fields;
//		var id = SingletonFactory.getInstance(Page)
//				.getRequest().getParams()['qid'];
//		var name = eventData.name;
//		var type = eventData.type;
//		var action = eventData.action;
//		var page = parseInt($("#" + uiid).attr("page"));
//		var rows = eventData.rows;
//		var curPlg = this;
//		var curUrl = this.root + type + "/" + action + "/"
//				+ name + "/" + id + "/page/" + page + "/rows/"
//				+ rows;
//		var result = null;
//		var sbj = SingletonFactory.getInstance(Subject);
//		$.ajax({
//			url : curUrl,
//			async : false,
//			success : function(ret) {
//				ret = $.parseJSON(ret);
//				ret = ret.result;
//				if (ret == undefined || ret == "error") {
//					sbj.notifyEvent("NotifyGlobal",
//							"Không lấy thêm được!");
//					return;
//				}
//				result = ret;
//			}
//		});
//
//		var resultUI = $("<div></div>");
//		// shit
//		result = result.answers;
//
//		var count = 0;
//		for ( var key in result) {
//			var curObj = result[key];
//			count++;
//			var objParam = {};
//			for ( var field in templateFields) {
//				var fName = templateFields[field];
//				var fArr = Array();
//				if (fName.indexOf(".") != -1) {
//					fArr = fName.split(".");
//					objParam[field] = curObj[fArr[0]][fArr[1]]
//							|| "";
//				} else {
//					objParam[field] = curObj[fName] || "";
//				}
//
//			}
//			resultUI.append(tmpl(templateID, objParam));
//		}
//		resultUI.children().children().hide();
//		$("#" + parentID)
//				.append(resultUI.children().children());
//
//		// Presenting only
//		var numChild = $("#" + parentID).children().length;
//		var from = numChild - count;
//		$("#" + parentID).children().slice(from, numChild)
//				.slideToggle("fast");
//
//		var sum = page + count;
//		$("#" + uiid).attr("page", sum);
//
//		var sbj = SingletonFactory.getInstance(Subject);
//		sbj.notifyEvent("FixBrokenImage");
//		sbj.notifyEvent("BindingChangeAnswer");
//		sbj.notifyEvent("ShowBio", {'qid': id});
//		sbj.notifyEvent("RenderBioEditLink", {'qid': id});
//	},
//
//	onCreateNewTopicContext : function(eventData) {
//		this.checkUserLogin(eventData, "CreateNewContext");
//	},

	checkUserLogin : function(eventData, type) {
		var evtArgs = {};
		evtArgs.type = type;
		evtArgs.evtData = eventData;
		var sbj = SingletonFactory.getInstance(Subject);
		sbj.notifyEvent("NeedLogin", evtArgs);
	},

	onLoginSuccess : function(eventData) {
		var type = eventData.type;
		var evtArgs = eventData.evtData;
		if (type != undefined && evtArgs != undefined) {
			switch (type) {
			case "VoteAnswerIncrease":
				this.voteAnswerIncrease(evtArgs);
				break;
			case "VoteAnswerDecrease":
				this.voteAnswerDecrease(evtArgs);
				break;
//			case "TopicAdded":
//				this.topicAdded(evtArgs);
//				break;
//			case "TopicDeleted":
//				this.topicDeleted(evtArgs);
//				break;
//			case "CreateNewContext":
//				this.createNewContextSuccess(evtArgs);
//				break;
			case "VoteUpQuestion":
				this.voteUpQuestion(evtArgs);
				break;
			case "VoteDownQuestion":
				this.voteDownQuestion(evtArgs);
				break;
			default:
				break;
			}
		}
//		this.onCheckTopicEditable();
	},

//	createNewContextSuccess : function() {
//		var subject = SingletonFactory.getInstance(Subject);
//		var rq = SingletonFactory.getInstance(Page)
//				.getRequest();
//		var params = rq.getParams();
//		var request = new Request("TopicCreatePage", "", {
//			"pageCallBack" : "Question",
//			"needParam" : true,
//			"paramName" : "qid",
//			"paramVal" : params['qid']
//		});
//		subject.notifyEvent('RequestRoute', request);
//	},
//	
//	onCheckTopicEditable: function(eventData){
//		var currentUid = SingletonFactory.getInstance(Application).getSystemProperties().get("user.id");
//		$(".extension-point[extensionName='CheckTopicEditable']").each(function(index,value){
//			 var uid = $(value).attr("uid");
//			 if(uid == currentUid){
//				$(value).find(".delToken").show(); 	
//			 } else {
//			 	$(value).find(".delToken").hide();
//			 }
//		});
//	},
//	
//	onCheckTopicEditableZone: function(eventData){
//		var zone = eventData.zone;
//		var currentUid = SingletonFactory.getInstance(Application).getSystemProperties().get("user.id");
//		$(zone).find(".extension-point[extensionName='CheckTopicEditable']").each(function(index,value){
//			 var uid = $(value).attr("uid");
//			 if(uid == currentUid){
//				$(value).find(".delToken").show(); 	
//			 } else {
//			 	$(value).find(".delToken").hide();
//			 }
//		});
//	},
//
//	onHtmlUpdated : function() {
//		var id = SingletonFactory.getInstance(Application)
//				.getSystemProperties().get("user.id");
//		$(".extension-point[extensionName='ProfileImageCheck'][uid='"+ id + "']")
//			.css("background-color", "#FAFAFA");
//	}

}).implement(PluginInterface).implement(AjaxInterface);

CommentPlugin = Class.extend({
	init : function() {
		this.name = "CommentPlugin";
		this.props = SingletonFactory.getInstance(Application).getSystemProperties();
		this.root = this.props.get("host.root");
	},
	
	onAnswerBuilt: function(evenData)	{
		var uid = this.props.get('user.login');
		var obj = this;
		if (uid != 0)	{
			$('.extension-point[extensionName="AnswerExtension"]').each(function()	{
				if ($(this).find('[flag="AnsComment"]').length > 0)	{
					return;
				}
				var aid = $(this).attr('aid');
				var uid = $(this).attr('uid');
				$(this).find('.ans-control .extension_place').append(tmpl('CommentPlugin-Control', {uid: uid, aid: aid}));
				$(this).find('.ans-extension-area').append(tmpl('CommentPlugin-Area', {uid: uid, aid: aid}));
				obj.onAjax('answer', 'get-no-comment', {aid: aid}, 'GET', {
					'onSuccess': function(ret)	{
						$('#CommentControl-'+uid+'-'+aid).html('Bàn luận thêm ('+ret+')');
					}
				});
			});
		}
	},

	onShowComment: function(eventData){
		var uid = eventData.uid;
		var aid = eventData.aid;
		
		var visible = true;
		var commentArea = $('.extension-point[extensionName="AnswerExtension"][aid="'+aid+'"] .ans-extension-area .comment-outer');
		if (!commentArea.is(':visible'))	{
			visible = false;
			var subject = SingletonFactory.getInstance(Subject);
			subject.notifyEvent('AnswerExtensionControlChanged');
		}
		commentArea.slideToggle();
		if (!visible)	{
			this.reloadComment(uid, aid);
		}
	},
	
	reloadComment: function(uid, aid, cache)	{
		if (cache == undefined)
			cache = true;
		var obj = this;
		var commentArea = $('.extension-point[extensionName="AnswerExtension"][aid="'+aid+'"] .ans-extension-area .comment-outer');
		$(commentArea).find('.comment-list').html('');
		var sbj = SingletonFactory.getInstance(Subject);
		this.onAjax('answer', 'get-all-comments', {aid:aid}, 'GET', {
			'onSuccess': function(ret){
				//fetch comment number
				obj.bindNumberOfComment(aid,uid,ret.length);
				
				// dump to list
				for(var key in ret){
					var objParam = {};
					objParam.content = ret[key]["content"];
					objParam.date = ret[key]["since"];
					objParam.uid = ret[key]["userId"];
					objParam.username = ret[key]["name"] ;
					objParam.avatar = ret[key]["avatar"];
					var template = tmpl("CommentPlugin-Item",objParam);
					$(commentArea).find('.comment-list').append(template);
				}
				var checkImg = {};
				checkImg.zone = $(commentArea).find('.comment-list');
				sbj.notifyEvent("RequestProfileImageCheck", checkImg);
			}
		}, cache, 300000);
	},
	
	bindNumberOfComment: function(aid, uid, data){
		$('#CommentControl-'+uid+'-'+aid).html("Bàn luận thêm ("+data+")");
	},
	
	onAddComment: function(eventData){
		var aid = eventData.aid;
		var uid = eventData.uid;
		var commentArea = $('.extension-point[extensionName="AnswerExtension"][aid="'+aid+'"] .ans-extension-area .comment-outer');
		var textarea = commentArea.find('.comment-content');
		var content = textarea.val().trim();
		if(content == "")
			return;
		var obj = this;
		this.onAjax('answer', 'add-new-comment', {aid:aid, content:content}, 'POST', {
			'onSuccess': function(ret){
				textarea.val("");
				obj.reloadComment(uid, aid, false);
			}
		});
	}
}).implement(PluginInterface).implement(AjaxInterface);

ImproveAnswerPlugin = Class.extend({
	init: function()	{
		this.name = "ImproveAnswerPlugin";
	},
	
	onSendImprovement: function(eventData)	{
		var id = eventData.id;
		var subject = SingletonFactory.getInstance(Subject);
		var type = $('#ImproveAnswerPlugin-Select option:selected').val();
		this.onAjax('answer', 'add-negative-comment', {id: id, type: type}, 'GET', {
			'onSuccess': function(ret)	{
				subject.notifyEvent('PopupRemove', {id: 'ImproveAnswerPlugin'});
				subject.notifyEvent('NotifyGlobal', 'Bạn đã gửi góp ý thành công!');
				$('#ImproveControl-'+id).remove();
			}
		});
	},
	
	onImproveControlClick: function(eventData)	{
		var aid = eventData.aid;
		var subject = SingletonFactory.getInstance(Subject);
		subject.notifyEvent('ShowPopup', {id: 'ImproveAnswerPlugin', title: 'Góp ý cho câu trả lời', content: tmpl('ImproveAnswerPlugin-Form', {aid: aid})});
	},
	
	onAnswerBuilt: function()	{
		var loggedin = SingletonFactory.getInstance(Application).getSystemProperties().get('user.login');
		if (loggedin == 0)
			return;
		var obj = this;
		var cuid = SingletonFactory.getInstance(Application).getSystemProperties().get('user.id');
		$('.extension-point[extensionName="AnswerExtension"]').each(function()	{
			if ($(this).find('[flag="ImproveAnswer"]').length > 0)	{
				return;
			}
			
			$(this).append('<span flag="ImproveAnswer"></span>');
			var aid = $(this).attr('aid');
			var uid = $(this).attr('uid');
			if (uid == cuid)
				return;
			var dom = this;
			obj.onAjax('answer', 'has-sent-negative-comment', {id: aid}, 'GET', {
				'onSuccess': function(ret)	{
					if (ret == 1)	{
						return;
					}
					$(dom).find('.ans-control .extension_place').append(tmpl("ImproveAnswerPluginTmpl", {aid: aid}));
				}
			});
		});
	}
}).implement(PluginInterface).implement(AjaxInterface);

ImproveQuestionPlugin = Class.extend({
	init: function()	{
		this.name = "ImproveQuestionPlugin";
	},
	
	onQuestionBuilt: function(eventData){
		var loggedin = SingletonFactory.getInstance(Application).getSystemProperties().get('user.login');
		if (loggedin == 0)
			return;
		var obj = this;
		var cuid = SingletonFactory.getInstance(Application).getSystemProperties().get('user.id');
		var qid = eventData.id;
		var uid = eventData.userID;
		$('.extension-point[extensionName="QuestionTask"]').each(function()	{
			if ($(this).find('[flag="ImproveQuestion"]').length > 0)	{
				return;
			}
			
			$(this).append('<span flag="ImproveQuestion"></span>');
			if (uid == cuid)
				return;
			var dom = this;
			obj.onAjax('question', 'has-sent-negative-comment', {id: qid}, 'GET', {
				'onSuccess': function(ret)	{
					if (ret == 1)	{
						return;
					}
					$(dom).prepend(tmpl("ImproveQuestionPluginTmpl", {qid: qid}));
				}
			});
		});
	},
	
	onSendQuestionImprovement: function(eventData)	{
		var id = eventData.id;
		var subject = SingletonFactory.getInstance(Subject);
		var type = $('#ImproveQuestionPlugin-Select option:selected').val();
		this.onAjax('question', 'add-negative-comment', {id: id, type: type}, 'GET', {
			'onSuccess': function(ret)	{
				subject.notifyEvent('PopupRemove', {id: 'ImproveQuestionPlugin'});
				subject.notifyEvent('NotifyGlobal', 'Bạn đã gửi góp ý thành công!');
				$('#ImproveQuestionControl-'+id).remove();
			}
		});
	},
	
	onImproveQuestionControlClick: function(eventData)	{
		var qid = eventData.qid;
		var subject = SingletonFactory.getInstance(Subject);
		subject.notifyEvent('ShowPopup', {id: 'ImproveQuestionPlugin', title: 'Góp ý cho câu hỏi', content: tmpl('ImproveQuestionPlugin-Form', {qid: qid})});
	}
}).implement(PluginInterface).implement(AjaxInterface);

QuestionCommentPlugin = Class.extend({
	init: function()	{
		this.name = "QuestionCommentPlugin";
	},
	
	onQuestionBuilt: function(eventData){
		var loggedin = SingletonFactory.getInstance(Application).getSystemProperties().get('user.login');
		if (loggedin == 0)
			return;
		var obj = this;
		var cuid = SingletonFactory.getInstance(Application).getSystemProperties().get('user.id');
		var qid = eventData.id;
		var uid = eventData.userID;
		$('.extension-point[extensionName="QuestionTask"]').each(function()	{
			if ($(this).find('[flag="QuestionComment"]').length > 0)	{
				return;
			}
			
			$(this).append('<span flag="QuestionComment"></span>');
			if (uid == cuid)
				return;
			var dom = this;
			obj.onAjax('question', 'get-no-comment', {id: qid}, 'GET', {
				'onSuccess': function(ret)	{
					$(dom).append(tmpl("QuestionCommentControlTmpl", {qid: qid, no_comment: ret}));
				}
			});
		});
	},
	
	onSendQuestionImprovement: function(eventData)	{
		var id = eventData.id;
		var subject = SingletonFactory.getInstance(Subject);
		var type = $('#ImproveQuestionPlugin-Select option:selected').val();
		this.onAjax('question', 'add-negative-comment', {id: id, type: type}, 'GET', {
			'onSuccess': function(ret)	{
				subject.notifyEvent('PopupRemove', {id: 'ImproveQuestionPlugin'});
				subject.notifyEvent('NotifyGlobal', 'Bạn đã gửi góp ý thành công!');
				$('#ImproveQuestionControl-'+id).remove();
			}
		});
	},
	
	onQuestionCommentControlClick: function(eventData)	{
		var visible = true;
		var commentArea = $('#QuestionCommentArea');
		if (!commentArea.is(':visible'))	{
			visible = false;
			var subject = SingletonFactory.getInstance(Subject);
			subject.notifyEvent('AnswerExtensionControlChanged');
		}
		commentArea.slideToggle();
		if (!visible)	{
			this.reloadComment(qid);
		}
	},
	
	reloadComment: function(uid, aid, cache)	{
		if (cache == undefined)
			cache = true;
		var obj = this;
		var commentArea = $('.extension-point[extensionName="AnswerExtension"][aid="'+aid+'"] .ans-extension-area .comment-outer');
		$(commentArea).find('.comment-list').html('');
		var sbj = SingletonFactory.getInstance(Subject);
		this.onAjax('answer', 'get-all-comments', {aid:aid}, 'GET', {
			'onSuccess': function(ret){
				//fetch comment number
				obj.bindNumberOfComment(aid,uid,ret.length);
				
				// dump to list
				for(var key in ret){
					var objParam = {};
					objParam.content = ret[key]["content"];
					objParam.date = ret[key]["since"];
					objParam.uid = ret[key]["userId"];
					objParam.username = ret[key]["name"] ;
					objParam.avatar = ret[key]["avatar"];
					var template = tmpl("CommentPlugin-Item",objParam);
					$(commentArea).find('.comment-list').append(template);
				}
				var checkImg = {};
				checkImg.zone = $(commentArea).find('.comment-list');
				sbj.notifyEvent("RequestProfileImageCheck", checkImg);
			}
		}, cache, 300000);
	}
}).implement(PluginInterface).implement(AjaxInterface);
/**
 * 
 */

EditPendingQuestionsPlugin = Class
		.extend(
				{
					init : function() {
						this.name = "EditPendingQuestionsPlugin";
						this.app = SingletonFactory.getInstance(Application);
						this.root = this.app.getSystemProperties().get(
								"host.root");
						this.topics = this.app.getSystemProperties().get(
								"memcached.topics");
						this.addedTopics = null;
						this.pendingQuestion = {};
					},

					// From AnswerPortlet
					getAjaxAllTopics: function(){
						var curPlt = this;
						var curUrl = this.root + "catchword/get-all-catchwords/";
						$.ajax({url:curUrl, async:false , success: function(ret){
							ret = $.parseJSON(ret);
							ret = ret.result;
							if(ret == undefined || ret == "error"){
								return;
							}
							curPlt.topics = ret;
							SingletonFactory.getInstance(Application).getSystemProperties().set("memcached.topics",ret);
						}});
						this.topics = curPlt.topics;
					},
					
					// From AnswerPortlet
					getAjaxTopicQuestion: function(){
						var curPlt = this;
						var curUrl = this.root + "question/get-all-un-auth-catchwords-question/qid/" + this.questionID;
						$.ajax({url:curUrl, async:false, success: function(ret){
							ret = $.parseJSON(ret);
							ret = ret.result;
							if(ret == undefined || ret == "error"){
								return;
							}
							curPlt.topicsQuestion = ret;
						}});
						this.topicsQuestion = curPlt.topicsQuestion;
					},
					
					// From AnswerPortlet
					buildQuestionTopics: function(){
						var result = $("<div><div></div></div>");
						var topicAdded = Array();
						for ( var key in this.topicsQuestion) {
							var objParam = {};
							var curObj = this.topicsQuestion[key];
							objParam.tid = generateId("tt");
							objParam.content = curObj['catchword'];
							objParam.cid = curObj['id'];
							topicAdded[this.questionID + "-" + curObj['id']] = objParam.tid;
							var newTp = tmpl("AnswerPortlet-Topic",objParam);
							result.children().append(newTp);
						}
						// fetch to cache
						var sysProp = SingletonFactory.getInstance(Application).getSystemProperties();
						sysProp.set("memcached.addedTopics",topicAdded);
						this.pendingQuestion.topics = result.children();
					},
					
					// From AnswerPortlet
					buildAllTopics: function(){
						var result = $("<div><div></div></div>");
						for ( var key in this.topics) {
							var curObj = this.topics[key];
							var newTp = $("<option value='"+curObj['id']+"'>"+curObj['catchWord']+"</option>");
							result.children().append(newTp);
						}
						this.pendingQuestion.avaiTopics = result.children();
					},
					
					// In question Pending, no other is found
					onEditPendingQuestion: function(eventData){
						this.checkUserLogin(eventData, "EditPendingQuestion");
						
					},
					
					editPendingQuestion: function(eventData){
						this.questionID = eventData.id;
						
						if(this.topics == undefined){
							this.getAjaxAllTopics();
						}
						this.getAjaxTopicQuestion();
						// dump topicsQuestions
						this.buildQuestionTopics();
						
						// dump topics
						this.buildAllTopics();
						
						// get data from cached in profilePortlet
						var pendingQuestions = SingletonFactory.getInstance(Application).getSystemProperties().get("memcached.pendingQuestions");
						var objParam = {};
						objParam.topics = this.pendingQuestion.topics || Array();
						objParam.avaiTopics = this.pendingQuestion.avaiTopics || Array();
						objParam.qcontent = pendingQuestions[this.questionID].title;
						objParam.qdetail =  pendingQuestions[this.questionID].content;
						objParam.qid =  this.questionID;
						var template = tmpl("QuestionPendingPortlet-EditQuestion", objParam);
						var tmp = $(".questionEmphasized[qid='"+this.questionID+"']").children("span");
						pendingQuestions[this.questionID]['span'] = tmp;
						SingletonFactory.getInstance(Application).getSystemProperties().set("memcached.pendingQuestions",pendingQuestions);
						$(".questionEmphasized[qid='"+this.questionID+"']").empty().append($(template));
					},
					
					//
					onSavePendingQuestions: function(eventData){
						var id = eventData.id;	
						var parent = eventData.parent;
						var title = $("#editquestion-title-" + id).val();
						var content = $("#editquestion-content-" + id).val();
						
						var curUrl = this.root + "question/update-un-auth-question";
						var sbj = SingletonFactory.getInstance(Subject);
						$
						.ajax({
							url : curUrl,
							type : "POST",
							data : {
								"content" : content,
								"title" : title,
								"qid" : id
							},
							success : function(ret) {
								var cache = SingletonFactory.getInstance(Application).getSystemProperties().get("memcached.pendingQuestions");
								var span = cache[id]['span'];
								cache[id].title = title;
								cache[id].content = content;
								SingletonFactory.getInstance(Application).getSystemProperties().set("memcached.pendingQuestions",cache);
								$(".questionEmphasized[qid='"+id+"']").empty().append("<strong>" + title + "</strong>").append(span);
								sbj.notifyEvent("NotifyGlobal",
										"Sửa thành công");
							},
							error : function(ret) {
								sbj.notifyEvent("NotifyGlobal","Sửa thất bại");
							}
						});
						
					},
					
					onCancelPendingQuestions: function(eventData){
						var id = eventData.id;	
						var cache = SingletonFactory.getInstance(Application).getSystemProperties().get("memcached.pendingQuestions");
						var span = cache[id]['span'];
						var title = cache[id].title;
						$(".questionEmphasized[qid='"+id+"']").empty().append("<strong>" + title + "</strong>").append(span);
					},

					onToggleDownEditTopic : function(eventData) {
						var id = eventData.id;
						$("#" + id).slideToggle('fast');
						$("#" + id + " #bkp-topic-search-new").val("");
						this.buildTopics(SingletonFactory.getInstance(
								Application).getSystemProperties().get(
								"memcached.topics"));
					},

					onToggleUpEditTopic : function(eventData) {
						var id = eventData.id;
						// $("#" + id).children("input[type=text]").val("");
						$("#" + id).slideToggle('fast');
					},

					// login
					onTopicAdded : function(eventData) {
						this.checkUserLogin(eventData, "TopicAdded");
					},

					topicAdded : function(eventData) {
						var id = eventData.id;
						// dang sau la pending question
						var questionID = this.questionID;
						var selected = $("#" + id + "  option:selected");
						for ( var i = 0; i < selected.length; i++) {
							var value = $(selected[i]).val();
							var text = $(selected[i]).text();

							// TODO: đưa value lên server
							// đưa value vào trong list
							// Nếu trong list có rồi thì thoi
							var topicAdded = this.app.getSystemProperties()
									.get("memcached.addedTopics");
							if (topicAdded[questionID + "-" + value] != undefined) {
								return;
							}

							var objParam = {};
							objParam.tid = generateId("tt");
							objParam.content = text;
							objParam.cid = value;
							var newTp = tmpl("AnswerPortlet-Topic", objParam);
							$("#" + id).parent().siblings(
									".bkp_question_topics").append(newTp);

							// set back to memcached
							topicAdded[questionID + "-" + value] = objParam.tid;
							var sysProp = this.app.getSystemProperties();
							sysProp.set("memcached.addedTopics", topicAdded);

							// dump to server
							var curUrl = this.root
									+ "question/add-catchword-un-auth/qid/"
									+ questionID + "/cid/" + value;
							var sbj = SingletonFactory.getInstance(Subject);
							$.ajax({
								url : curUrl,
								data : {},
								success : function(ret) {
									sbj.notifyEvent("NotifyGlobal",
											"Thêm thành công");
								},
								error : function() {
									sbj.notifyEvent("NotifyGlobal",
											"Thêm thất bại");
								}
							});
						}
					},

					onTopicDeleted : function(eventData) {
						this.checkUserLogin(eventData, "TopicDeleted");
					},

					topicDeleted : function(eventData) {
						var id = eventData.id;
						var questionID = this.questionID;
						var value = $("#" + id).attr("cid")
						var text = $("#" + id + " label").text();

						var topicAdded = this.app.getSystemProperties().get(
								"memcached.addedTopics");
						topicAdded[questionID + "-" + value] = undefined;
						var sysProp = this.app.getSystemProperties();
						sysProp.set("memcached.addedTopics", topicAdded);

						$("#" + id).remove();
						// dump to server
						var curUrl = this.root
								+ "question/remove-un-auth-catchword/qid/" + questionID
								+ "/cid/" + value;
						var sbj = SingletonFactory.getInstance(Subject);
						$
								.ajax({
									url : curUrl,
									data : {},
									success : function(ret) {
										sbj.notifyEvent("NotifyGlobal",
												"Xóa thành công");
									},
									error : function() {
										sbj.notifyEvent("NotifyGlobal",
												"Xóa thất bại");
									}
								});
					},

					onTopicChanged : function(eventData) {
						var id = eventData.id;
						var pid = eventData.pid;
						var value = $("#" + id).val().trim().replace("  ", " ")
								.toLowerCase();
						var e = eventData.e;
						var topics = SingletonFactory.getInstance(Application)
								.getSystemProperties().get("memcached.topics");
						var arr = Array();
						var newTopics = null;
						var isEqual = false;
						for ( var key in topics) {
							var curObj = topics[key];
							var content = curObj['catchWord'].toLowerCase();
							var match = new RegExp(value);
							if (content == value) {
								isEqual = true;
							}
							if (match.test(content)) {
								arr.push(curObj);
							}
						}

						newTopics = this.buildTopics(arr);
						if (newTopics != null) {
							$("#" + pid).empty().append(newTopics.children());
						}
					},

					buildTopics : function(arr) {
						var result = $("<div><div></div></div>");
						for ( var key in arr) {
							var curObj = arr[key];
							var newTp = $("<option value='" + curObj['id']
									+ "'>" + curObj['catchWord'] + "</option>");
							result.children().append(newTp);
						}
						return result.children();
					},

					onCreateNewTopicContext : function(eventData) {
						this.checkUserLogin(eventData, "CreateNewContext");
					},

					checkUserLogin : function(eventData, type) {
						var evtArgs = {};
						evtArgs.type = type;
						evtArgs.evtData = eventData;
						var sbj = SingletonFactory.getInstance(Subject);
						sbj.notifyEvent("NeedLogin", evtArgs);
					},

					onRejectChanges : function(eventData) {
						var curUid = eventData.uid;
						var curAid = eventData.aid;
						$("#extension-content-plhld-" + curAid + "-" + curUid)
								.children().hide('fast');
					},

					onLoginSuccess : function(eventData) {
						var type = eventData.type;
						var evtArgs = eventData.evtData;
						if (type != undefined && evtArgs != undefined) {
							switch (type) {
							case "TopicAdded":
								this.topicAdded(evtArgs);
								break;
							case "TopicDeleted":
								this.topicDeleted(evtArgs);
								break;
							case "SubmitAnswer":
								this.submitAnswer(evtArgs);
								break;
							case "AcceptChanges":
								this.acceptChanges(evtArgs);
								break;
							case "CreateNewContext":
								this.createNewContextSuccess(evtArgs);
								break;
							case "EditPendingQuestion":
								this.editPendingQuestion(evtArgs);
								break;
							default:
								break;
							}
						}
					},

					createNewContextSuccess : function() {
						var subject = SingletonFactory.getInstance(Subject);
						var rq = SingletonFactory.getInstance(Page)
								.getRequest();
						var params = rq.getParams();
						var request = new Request("TopicCreatePage", "", {
							"pageCallBack" : params["page"],
							"needParam" : true
						});
						subject.notifyEvent('RequestRoute', request);
					},

					onHtmlUpdated : function() {
						var id = SingletonFactory.getInstance(Application)
								.getSystemProperties().get("user.id");
						$(
								".extension-point[extensionName='ProfileImageCheck'][uid='"
										+ id + "']").css("background-color",
								"#FAFAFA");
					}

				}).implement(PluginInterface);

/**
 * 
 */

MoreContentPlugin = Class.extend(
		{
			init : function() {
				this.name = "MoreContentPlugin";
			},

			onHtmlRendered : function(eventData) {
				//this.render(eventData);
			},
			
			onCheckMoreLessContent: function(eventData){
				this.render(eventData);
			},
			
			render : function(eventData) {
				var showChar = 240;
				var ellipsestext = "...";
//				var moretext = "(more)";
//				var lesstext = "(less)";
				var index = 0;
				$('.extension-point[extensionName="MoreContent"]').each(function() {
					var content = $(this).text().substr(0, showChar).trim();
					$(this).html(content+ellipsestext);
//					index++;
//				    var content = $(this).html();
//				    var curChildren = $(this).children();
//				    var lengthChildren = curChildren.length;
//				    if(lengthChildren == 0){
//				  	   if(content.length > showChar) {
//				           var c = content.substr(0, showChar);
//				           var h = content.substr(showChar-1, content.length - showChar);
//				           var html = c + '<span class="moreellipses">' + ellipsestext+ '&nbsp;</span><span class="morecontent"><span>' + h + '</span>&nbsp;&nbsp;<a href="" class="morelink">' + moretext + '</a></span>';
//				           $(this).html(html);
//				       }
//				    } 
//				    else {
//						for(var i=0; i< lengthChildren; i++){
//							var curContent = $(curChildren[i]).html().trim();
//							if(curContent == ""){
//								continue;
//							}
//							
//							var tmp = $("<div></div>").append(curContent.substring(0,showChar)); 
//				    		var other = $("<div></div>").append(curChildren);
//				    		if(content.length > showChar) {
//				    			var html = '<span class="showmorecontent">' + tmp.html() + '</span><span class="moreellipses">' + ellipsestext+ '&nbsp;</span><span class="hiddencontentwithtags" style="display:none">' + other.html() + '</span><span class="morecontentwithtags"><a class="morelinkwithtags">' + moretext + '</a></span>';
//				    			$(this).html(html);
//					    	}
//							break;
//						}
//				    }
				   });
				
//				   $(".morelink").click(function(){
//				       if($(this).hasClass("less")) {
//				           $(this).removeClass("less");
//				           $(this).html(moretext);
//				       } else {
//				           $(this).addClass("less");
//				           $(this).html(lesstext);
//				       }
//				       $(this).parent().prev().toggle();
//				       $(this).prev().toggle();
//				       return false;
//				   });
				   
//				   $(".morelinkwithtags").click(function(){
//				       var hiddenItem = $(this).parent().siblings(".hiddencontentwithtags");
//				       var hiddenItemContent = hiddenItem.html();
//				       var showItem = $(this).parent().siblings(".showmorecontent");
//				       var shownItemContent = showItem.html();
//				       hiddenItem.empty().append(shownItemContent);
//				       showItem.empty().append(hiddenItemContent);
//
//				       if($(this).hasClass("lessContent")) {
//				           $(this).removeClass("lessContent");
//				           $(this).parent().siblings(".moreellipses").html(ellipsestext+"&nbsp;");
//				           $(this).html(moretext);
//				       } else {
//				           $(this).addClass("lessContent");
//				           $(this).parent().siblings(".moreellipses").html("");
//				           $(this).html(lesstext);
//				       }
//				       return false;
//				   });
			}
			
//			onCheckMoreLessContent: function(eventData){
//				var showChar = 120;
//				var ellipsestext = "...";
//				var moretext = "(more)";
//				var lesstext = "(less)";
//				var index = 0;
//				
//				$(eventData).find('.show_more_content').each(function(index,value) {
//					value = $(value);
//					index++;
//				    var content = $(value).html();
//				    var curChildren = $(value).children();
//				    var lengthChildren = curChildren.length;
//				    if(lengthChildren == 0){
//				  	   if(content.length > showChar) {
//				           var c = content.substr(0, showChar);
//				           var h = content.substr(showChar-1, content.length - showChar);
//				           var div = $("<div></div>");
//				           var a1 = $(c + '<span class="moreellipses">' + ellipsestext+ '&nbsp;</span>');
//				           var a2 = $('<span class="morecontent"><span>' + h + '</span>&nbsp;&nbsp;</span>');
//				           var a3 = $('<a href="" class="morelink">' + moretext + '</a>');
//				           a3.click(function(){
//				        	   if($(this).hasClass("less")) {
//						           $(this).removeClass("less");
//						           $(this).html(moretext);
//						       } else {
//						           $(this).addClass("less");
//						           $(this).html(lesstext);
//						       }
//						       $(this).parent().prev().toggle();
//						       $(this).prev().toggle();
//						       return false;
//				           });
//				           $(a2).append(a3);
//				           div.append(a1).append(a2);
//				           $(value).empty.append(div.children());
//				       }
//				    } 
//				    else {
//				    	var tmp = $("<div></div>").append($(curChildren[0]).html().substring(0,showChar)); 
//				    	var other = $("<div></div>").append(curChildren);
//				    	if(content.length > showChar) {
//				    		var a1 = $('<span class="showmorecontent">' + tmp.html() + '</span><span class="moreellipses">' + ellipsestext+ '&nbsp;</span><span class="hiddencontentwithtags" style="display:none">' + other.html() + '</span>');
//				    		var a2 = $('<span class="morecontentwithtags"></span>');
//				    		var a3 = $('<a class="morelinkwithtags">' + moretext + '</a>');
//				    		a3 = $(a3).click(function(){console.log("adsf");
//				    			var hiddenItem = $(this).parent().siblings(".hiddencontentwithtags");
//							       var hiddenItemContent = hiddenItem.html();
//							       var showItem = $(this).parent().siblings(".showmorecontent");
//							       var shownItemContent = showItem.html();
//							       hiddenItem.empty().append(shownItemContent);
//							       showItem.empty().append(hiddenItemContent);
//
//							       if($(this).hasClass("lessContent")) {
//							           $(this).removeClass("lessContent");
//							           $(this).parent().siblings(".moreellipses").html(ellipsestext+"&nbsp;");
//							           $(this).html(moretext);
//							       } else {
//							           $(this).addClass("lessContent");
//							           $(this).parent().siblings(".moreellipses").html("");
//							           $(this).html(lesstext);
//							       }
//							       return false;
//				    		});
//				    		a2 = $(a2).append(a3);
//				    		$(value).empty().append($(a1)).append($(a2));
//					    } 
//				    }
//				   });
//			}
		}).implement(PluginInterface);
ProfileNameEditPlugin = Class.extend({
	init: function()	{
		this.name = "ProfileNameEditPlugin";
	},
	
	saveData: function(event)	{
		var target = event.target;
		var newValue = $(target).val().trim();
		var oldValue = $(target).attr('oldValue');
		if (newValue == "")	{
			newValue = oldValue;
		}
		$(target).parent().removeAttr('editing');
		$(target).parent().html(newValue);
		if (oldValue != newValue)	{
			this.onAjax('user-ajax', 'edit-name', {'name': newValue}, 'POST', {});
		}
	},
	
	onProfileEditOnBlur: function(event)	{
		this.saveData(event);
	},
	
	onProfileEditOnKeyup: function(event)	{
		var keycode = event.keyCode;
		if (keycode == 13)	{
			this.saveData(event);
		}
	},
	
	onProfileNameEditClick: function(event)	{
		var target = event.target;
		var editTarget = $(target).parent().siblings('#BriefInfoEditPortlet-ProfileName');
		if ($(editTarget).attr('editing') == 'editing')
			return;
		var old = $(editTarget).html();
		$(editTarget).attr('editing', 'editing');
		$(editTarget).html('<input type="text" oldValue="'+old+'" onkeyup="generateEvent(&apos;ProfileEditOnKeyup&apos;, event)" onblur="generateEvent(&apos;ProfileEditOnBlur&apos;, event)" value="'+old+'">');
		$(editTarget).find('input').focus();
	},

	renderEditLink: function()	{
		var obj = this;
		$('.extension-point[extensionName="ProfileName"]').each(function(index, value)	{
			if ($(value).find('div[flag="ProfileNameEdit"]').length>0)
				return;
			$(value).append(tmpl('ProfileNameEdit', {}));
		});
	},
	
	onHtmlUpdated: function()	{
		this.renderEditLink();
	}
}).implement(PluginInterface).implement(AjaxInterface);
/**
 * 
 */

SearchResHelperPlugin = Class.extend({
	init : function() {
		this.name = "SearchResHelperPlugin";
	},
	
	checkTopics: function(eventData){
		$('.extension-point[extensionName="CheckTopicsAvai"]').each(function(){
			var children = $(this).children("a"); 
			var length = children.length;
			var shown = 4;
			children.slice(shown,length).remove();
			if(length > shown){
				$(this).append("<label style='color:#666666'>...</label>");
			}
		});
	},

	checkContentAvai: function(eventData){
		$('.extension-point[extensionName="CheckContentAvai"]').each(function(){
			var html = $(this).find(".show_more_content").html().trim();
			if(html != ""){
				$(this).css("display","inline-block");
			}
		});
	},
	
	localCheckTopic: function(eventData){
		$(eventData).find('.extension-point[extensionName="CheckTopicsAvai"]').each(function(index,value){
			var children = $(value).children("a"); 
			var length = children.length;
			var shown = 4;
			children.slice(shown,length).remove();
			if(length > shown){
				$(value).append("<label style='color:#666666'>...</label>");
			}
		});
	},
	
	localCheckContentAvai: function(eventData){
		$(eventData).find('.extension-point[extensionName="CheckContentAvai"]').each(function(index,value){
			var html = $(value).find(".show_more_content").html().trim();
			if(html != ""){
				$(value).css("display","inline-block");
			}
		});
	},
	
	onHtmlRendered : function(eventData) {
		this.checkContentAvai(eventData);
		this.checkTopics(eventData);
	},
	
	onRequestCheckAnswerContent: function(eventData){
		this.localCheckContentAvai(eventData);
		this.localCheckTopic(eventData);
	}
}).implement(PluginInterface);
/**
 * @author Hung
 */
HungPDArticleTabPlugin = Class.extend({
	init: function()	{
		this.name = "HungPDArticleTabPlugin";
		this.type = undefined;
		//alert('cham chap qua');
		
	},
	onArticleSearchResultChangeType: function(eventData)	{
		this.type = eventData.type;
		//alert(this.type);
		this.refreshType();
		//alert('Nay thi onArticleSearchResultChangeType');
	},
	
	onArticleSearchResultChangeScope: function(eventData)	{
		this.scope = eventData.scope;
		this.refreshScope();
		//alert('Nay thi onSearchResultChangeScope');
	},
	refreshType: function()	{
		var type = this.type;
		$('a[type="tatca"]').removeClass('active');
		$('a[type="baibaokhoahoc"]').removeClass('active');
		$('a[type="chiasekinhnghiem"]').removeClass('active');
		$('a[type="baiphongvanhay"]').removeClass('active');
		$('a[type="cauhoichatluong"]').removeClass('active');
		if (type == 'tatca' || type == undefined)	{
			$('a[type="tatca"]').addClass('active');
		} else if (type == 'baibaokhoahoc')	{
			$('a[type="baibaokhoahoc"]').addClass('active');
		}		
		else if (type == 'chiasekinhnghiem')	{
			$('a[type="chiasekinhnghiem"]').addClass('active');
		} else if (type == 'baiphongvanhay')	{
			$('a[type="baiphongvanhay"]').addClass('active');
		}  else if (type == 'cauhoichatluong')	{
			$('a[type="cauhoichatluong"]').addClass('active');
		}
	},
	
	refreshScope: function()	{
		var scope = this.scope;
		$('a[scope="theoluongvote"]').removeClass('active');
		$('a[scope="theongaythang"]').removeClass('active');
		if (scope == 'theongaythang' || scope == undefined)	{
			$('a[scope="theongaythang"]').addClass('active');
		} else {
			$('a[scope="theoluongvote"]').addClass('active');
		}
	},
	onHtmlUpdated: function()	{
		$('.extension-point[extensionName="ArticleSearchResultTitle"]').each(function(index, value) {
			if ($(value).find('[flag="ArticleTab"]').length > 0)	{
			//cai nay dung de tranh truong hop cai tab bi load lai hai lan	
				return;
			}
			//alert('aaa');

			$(value).append(tmpl('ArticleTabTemplate', {}));
			//alert('HtmlUpdate');
		});
		
		$('.extension-point[extensionName="ArticleSearchResultPostTitle"]').each(function(index, value) {
			if ($(value).find('[flag="ArticleTab"]').length > 0)	{
				return;
			}
			//alert("aaaaaaaaaaaaaaa");
			$(value).append(tmpl('ArticleTabScopeTemplate', {}));
		});
		
		this.refreshScope();
		this.refreshType();
	},
	
	onEnd: function()	{
		$('#effective-area .tab-article').remove();
	}
}).implement(PluginInterface);

HungPDEditArticleButtonPlugin = Class.extend({
	init: function()	{
		this.name = "HungPDEditArticleButtonPlugin";
	},
	
	onMakeNewTargetedQuestion: function(eventData)	{
		var subject = SingletonFactory.getInstance(Subject);
		//var profileName = $(eventData.target).parents('.profile-count:first').siblings('.user-name').html();
		//var pid = SingletonFactory.getInstance(Page).getRequest().getParam('id');
		subject.notifyEvent('MakeNewQuestion', {profile: [{name: profileName, id: pid}]});
	},
	
	onHtmlUpdated: function()	{
		$('.extension-point[extensionName="HungPDEditArticleSpan"]').each(function(index,value)	{
			var props = SingletonFactory.getInstance(Application).getSystemProperties();
			var loggedIn = props.get('user.login');
			var pid = undefined;
			
			if (loggedIn == 1)	{
				
				var uid = props.get('user.id');
				pid = $(value).siblings('.HungPDEditArticleUserIDSpan').html();
				aid=$(value).siblings('.HungPDEditArticleIDSpan').html();
				isSelected=$(value).siblings('.HungPDEditArticleIsSelectedSpan').html();
				//alert(pid);
				//alert(isSelected);
				if ((uid != pid))		{	//same user
					return;
				}
				if (isSelected==1)		{	//same user
					return;
				}
			} else {
				return;
			}
			if ($(this).find('.[flag="HungPDEditArticleFlag"]').length > 0)	{
				return;
			}
			//alert("sss");
			$(this).append(tmpl('HungPDEditArticleButtonPluginTmpl', {'aid':aid}));
			
		});
	}
}).implement(PluginInterface);
HungPDDeleteArticleCommentPlugin = Class.extend({
	init: function()	{
		this.name = "HungPDDeleteArticleCommentPlugin";
	},
	
	
	onHtmlUpdated: function()	{
		$('.extension-point[extensionName="HungPDCommentArticleSpan"]').each(function(index,value)	{
			//alert("aaa");
			var props = SingletonFactory.getInstance(Application).getSystemProperties();
			var loggedIn = props.get('user.login');
			var userCommentID = undefined;
			var userCommentUserID = undefined;
			if(loggedIn==1)	{
				var uid = props.get('user.id');
				userCommentID=$(value).siblings('.HungPDCommentIDSpan').html();
				userCommentUserID = $(value).siblings('.HungPDCommentUserIDSpan').html();
				//alert(uid+"-"+userCommentUserID);
				if(uid!=userCommentUserID){
					return;
				}
				//alert($(value).html());
			} else{
				return;
			};
			if ($(value).find('.[flag="HungPDCommentFlag"]').length > 0)	{
				return;
			}
			
			 $(value).append(tmpl('HungPDDeleteArticleButtonPluginTmpl',{'commentID':userCommentID}));
		});
		return;
	}
}).implement(PluginInterface);

HungPDArticleVotePlugin = Class.extend({
	init: function()	{
		this.name = "HungPDArticleVotePlugin";
		//alert("aaa");
	},
	
	
	onHtmlUpdated: function()	{
		$('.extension-point[extensionName="HungPDVoteSpan"]').each(function(index,value)	{
			//alert("aaa");
			var props = SingletonFactory.getInstance(Application).getSystemProperties();
			var loggedIn = props.get('user.login');
			var authorUserID = undefined;
			var articleID = undefined;
			var needToType = undefined;
			var contentToAppend="";
			if(loggedIn==1)	{
				var uid = props.get('user.id');
				needToType=$(value).siblings('.HungPDVoteNeedToVoteSpan').html();
				authorUserID=$(value).siblings('.HungPDVoteAuthorIDSpan').html();
				articleID = $(value).siblings('.HungPDVoteArticleIDSpan').html();
				//alert(articleID+"-"+authorUserID+"-"+needToType);
				
				if(uid!=authorUserID){
					if(needToType==1){
						//alert("dsdasdsadas");
						contentToAppend=tmpl('HungPDArticleVoteButtonTmpl',{'articleID': articleID,'authorID':authorUserID});
					} else if(needToType==2){
						contentToAppend=tmpl('HungPDArticleUnVoteButtonTmpl',{'articleID': articleID,'authorID':authorUserID});						
						//alert(contentToAppend);
					}
					
				} else{
					return;
				}
				//alert($(value).html());
			} else{
				return;
			};
			if ($(value).find('.[flag="HungPDArticleVoteFlag"]').length > 0)	{
				return;
			}		
			//alert(contentToAppend);
			 $(value).append(contentToAppend);
		});
		return;
	}
}).implement(PluginInterface);

HungPDIsSelectedTabPlugin = Class.extend({
	init: function()	{
		this.name = "HungPDArticleVotePlugin";
		//alert("aaa");
		this.type=null;
	},
	onIsSelectedArticleChangeType: function(eventData)	{
		this.type = eventData.type;
		//alert(this.type);
		this.refreshType();
		//alert('Nay thi onArticleSearchResultChangeType');
	},
	
	refreshType: function()	{
		var type = this.type;
		//alert(type);
		$('a[type="dadang"]').removeClass('active');
		$('a[type="chuadang"]').removeClass('active');	
		if (type == 'dadang' || type == undefined)	{
			$('a[type="dadang"]').addClass('active');
			//alert("aa");
		} else if (type == 'chuadang')	{
			$('a[type="chuadang"]').addClass('active');
			//alert("bb");
		}		
	},
	
	onHtmlUpdated: function()	{
		var obj=this;
		$('.extension-point[extensionName="ArticleIsSelectedTab"]').each(function(index,value)	{
		//	alert("aaa");
			
			var props = SingletonFactory.getInstance(Application).getSystemProperties();
			var loggedIn = props.get('user.login');
			var authorID = undefined;
			var contentToAppend="";
			if(loggedIn==1)	{
				var uid = props.get('user.id');
				authorID=$(value).siblings('.HungPDIsSelectedAuthorIDSpan').html();
			//	alert(authorID);
				if(uid==authorID){				
					
				} else{
					return;
				}
				//alert($(value).html());
			} else{
				return;
			};
			//alert($(value).html());
			if ($(value).find('.[flag="ArticleIsSelectedTabFlag"]').length > 0)	{
				
				return;
			}		
			//alert(contentToAppend);
			//alert(tmpl('ArticleIsSelectedTabTemplate',{}));
			 $(value).append(tmpl('ArticleIsSelectedTabTemplate',{}));
			 obj.refreshType();
		});
		return;
	}
}).implement(PluginInterface);
TopicInterestAdderPlugin = Class.extend({
	init: function()	{
		this.name = "TopicInterestAdderPlugin";
	},
	
	onAddTopicToInterest: function(eventData)	{
		tid = SingletonFactory.getInstance(Page).getRequest().getParam('id');
		this.onAjax('user-ajax', 'add-single-interest', {id: tid}, 'POST', {
			'onSuccess': function()	{
				$(eventData.target).remove();
			}
		});
	},
	
	onHtmlUpdated: function()	{
		var obj = this;
		$('.extension-point[extensionName="TopicControl"]').each(function()	{
			if ($(this).find('[flag="TopicInterestAdder"]').length > 0)
				return;
			$(this).append('<span flag="TopicInterestAdder"></span>');
			//check login
			var props = SingletonFactory.getInstance(Application).getSystemProperties();
			var loggedIn = props.get('user.login');
			var dom = this;
			if (loggedIn == 1)	{
				tid = SingletonFactory.getInstance(Page).getRequest().getParam('id');
				obj.onAjax('catchword', 'user-has-interest', {'id': tid}, 'GET', {
					'onSuccess': function(ret)	{
						if (ret == 0)	{
							$(dom).append(tmpl('TopicInterestAdderTmpl', {}));
						}
					}
				});
			}
		});
	}
}).implement(PluginInterface).implement(AjaxInterface);
ArticleBrowserPortlet = Class.extend({
	init: function()	{
		this.name = "ArticleBrowserPortlet";
	},
	
	onBegin: function()	{
		this.registerObserver();
	},
	
	onTopMenuActive: function(name)	{
		if (name != this.name)	{
			$('#ArticleBrowserPortlet-ContentPlaceholder').html('');
			return;
		}
		var obj = this;
		this.onAjax('article', 'browse-articles', {}, 'GET', {
			'onSuccess': function(ret)	{
				obj.model = {};
				obj.model.articles = Array();
				for (var i in ret)	{
					obj.model.articles.push(ret[i]);
				}

				obj.getPortletPlaceholder().paintCanvas(obj.render());
				obj.requestForEffectiveResource('ContentPlaceholder').find('ul:first').addClass('first');
				obj.requestForEffectiveResource('ContentPlaceholder').find('ul:last').addClass('last');
			}
		}, true, 300000);
	},
	
	onReloadPage: function()	{
		this.checkActive();
	},
	
	run: function()	{
	},
	
	onEnd: function()	{
		this.unregisterObserver();
	}
}).implement(PortletInterface).implement(RenderInterface).implement(AjaxInterface).implement(ObserverInterface);
/**
 * @author Hung
 */
ArticleCommentPortlet = Class.extend({
	init : function() {
		this.name="ArticleCommentPortlet";
		this.articleID=null;
		this.articleDetail=null;
		this.model = {};
		this.root = SingletonFactory.getInstance(Application).getSystemProperties().get("host.root");
		this.uid = SingletonFactory.getInstance(Application).getSystemProperties().get("user.id");
		this.needMCE=true;
		this.activeCommentPage=1;
		this.totalCommentPage=0;
	},
	
	onBegin : function() {
		this.registerObserver();
		this.getArticleID();				
	},
	
	trim:function(s) {
			return s.replace(/^\s+/,"").replace(/\s+$/, "");
	},
	
	trimOfEditor:function(s){
		return s.replace(/^(&nbsp;)+/,"").replace(/(&nbsp;)+$/,"");
	},				
	
	convertHtmlDataToDisplay:function(s){
		return s.replace(/\\n/g,'').replace(/\\/g,'');
	},
	
	getArticleID : function(){
		this.articleID = this.getRequest().getParam('aid');
		if(this.articleID == null || this.articleID == undefined){
			var subject = SingletonFactory.getInstance(Subject);
			var request = new Request("ErrorPage", undefined, {"code":"888", "msg":"Lỗi","content":"Bài viết không tồn tại trong hệ thống!"}); 
			subject.notifyEvent('RequestRoute', request);
		}
	},
	
	getAjax:function(){
		var curPlt=this;
		this.onAjax('article','get-detail',{'id':this.articleID},'POST', {
			onSuccess: function(ret)	{
				curPlt.articleDetail=ret;		
				//curPlt.totalCommentPage=parseInt(curPlt.articleDetail.commentsID.length/5);
				curPlt.model = ret;
				var atype = ret.type;
				if (atype == 1)	{
					curPlt.model.atype = "Bài báo khoa học";
				} else if (atype == 2)	{
					curPlt.model.atype = "Bài chia sẻ kinh nghiệm";
				} else if (atype == 3) {
					curPlt.model.atype = "Câu hỏi hay";
				} else {
					curPlt.model.atype = "Bài phỏng vấn";
				}
				//curPlt.buildArticleComments();
				
				curPlt.getPortletPlaceholder().paintCanvas(curPlt.render());		
				//curPlt.initEditor();
				//curPlt.buildArticleCommentPagination();
				
				$('.simple_tab a').removeClass('active');
				$('.simple_tab a[type='+atype+']').addClass('active');
				var subject = SingletonFactory.getInstance(Subject);
				subject.notifyEvent('CleanFont');
			},
			onFailure:function(message){
				alert("thất bại rồi!");
			}
		});
	},
	
	initEditor : function()	{
		if(this.needMCE){
			this.requestForEffectiveResource('TextAreaContainer').html(this.renderView('MCE', {}));
			var curID = "HungPDArticleCommentPortlet-CommentTextEditor";
			//var sbj = SingletonFactory.getInstance(Subject);
			//sbj.notifyEvent("TinyEditorInit",{id : curID, content: ""});
		}
	},
	
	buildArticleContent:function(){
		var objParams={};
		var templateID=this.name+"-content-template";
		objParams.articleID=this.articleDetail.details.id;
		objParams.content=this.convertHtmlDataToDisplay(this.articleDetail.details.content);
		var contentContent=tmpl(templateID,objParams);
		this.model.articleContent=contentContent;
	},
	
	buildArticleComments:function(){
		var objParams={};
		
		var templateID=this.name+"-articleComment-template";
		var commentContent="";
		var commentList=this.articleDetail.commentsUserID;
		if(commentList.length==0){
			this.model.articleComments="";
			return;
		}
		start=(this.activeCommentPage-1)*5;
		while((start<(this.activeCommentPage*5))&&(start<this.articleDetail.commentsID.length)){
			objParams={};
			objParams.commentsID=this.articleDetail.commentsID[start];
			objParams.commentsUserID=this.articleDetail.commentsUserID[start];
			
			objParams.commentsUserFullName=this.articleDetail.commentsUserFullName[start];
			
			objParams.commentsCreatedDate=this.articleDetail.commentsCreatedDate[start];
			objParams.commentsContent=this.convertHtmlDataToDisplay(this.articleDetail.commentsContent[start]);
			commentContent+=tmpl(templateID,objParams);	
			start++;
		};
		this.model.articleComments=commentContent;
	},
	
	buildArticleCommentPagination:function(){
		var objParams={};
		objParams.activeCommentPage=this.activeCommentPage;
		objParams.totalCommentPage=this.totalCommentPage;
		if(this.totalCommentPage>1){			
		this.requestForEffectiveResource('NavigationLink').html(tmpl('HungPDArticleCommentPortlet-articleComment-SearchMoreButton-template',objParams));
		//alert(tmpl('HungPDArticleCommentPortlet-articleComment-SearchMoreButton-template',objParams));	
		}
	},
	
	onSubmitComment:function(eventData){
		var obj =this;// obj.name+"-CommentTextEditor";
        var str=this.trim($("#"+this.name+"-CommentTextEditor").val());
        if(this.trim(str).length>300){
        	alert("Rất tiếc! Hãy nhập đúng 300 từ");
        } else if(this.trim(str).length==0){
        	alert("Không nhập nội dung rỗng!");        	
        } else{
        	this.onAjax('article','add-article-comment',{'articleID':this.articleID,'content':str},'POST', {
        		onSuccess: function(ret)	{
					obj.run();					
				},
				onFailure:function(message){
					alert("thất bại rồi!");
				}
			});
        };        
	},
	
	onDeleteArticleComment:function(eventData){
		var obj=this;
		var cid=eventData.commentID;
		var result=window.confirm("Có chắc chắn xóa ?");
		if(!result){
			return;
		}
		this.onAjax('article','delete-article-comment',{'commentID':cid},'POST', 
		{'onSuccess': function(ret)	{
			obj.run();
		},
		onFailure:function(message){
			alert("thất bại rồi!");
		}});
	},
	
	onArticleVoteSubmit:function(){
		var subject = SingletonFactory.getInstance(Subject);
		subject.notifyEvent('NeedLogin', {type: "ArticleVoteSubmit"});
	},
	
	onLoginSuccess: function(eventData) {
		if (eventData.type != 'ArticleVoteSubmit')
			return;
		var obj=this;
		var articleID=this.articleID;
		this.onAjax('article','add-vote',{'id':articleID},'POST', {
			onSuccess: function(ret)	{
				var oldVote = parseInt(obj.requestForEffectiveResource('ArticleVote').html());
				obj.requestForEffectiveResource('ArticleVote').html(oldVote+1);
			}
		});
	},
	
	onUpdateCommentPage:function(eventData){
		if(this.activeCommentPage==1&&eventData.type==-1){
			return;
		}
		if(this.activeCommentPage==this.totalCommentPage&&eventData.type==1){
			return;
		}
		this.activeCommentPage+=eventData.type;
		this.run();
				
	},		
	
	run : function() {
		this.getAjax();
	},
	
	onReloadPage : function(){
		this.init();
		this.onBegin();
		this.run();
	},
	
	onEnd : function()	{
		this.unregisterObserver();
	}	
}).implement(RenderInterface).implement(PortletInterface).implement(ObserverInterface).implement(AjaxInterface);
/**
 * @author HungPDEditArticlePortlet: Portlet để nhập bài viết mới
 */
ArticleEditPortlet=Class.extend(
{
	init:function(){
		this.name="ArticleEditPortlet";
		//this.usingFacebox=true;
		this.topicValArray=Array();
		this.topicValInsertArray=Array();
		this.topicValDeleteArray=Array();
		this.topicTextArray=Array();
		this.articleID=-1;
		//alert("ubuntu");
		//hai cai bien nay de phuc vu cho text editor
		this.app = SingletonFactory.getInstance(Application);
		this.props = this.app.getSystemProperties();
					
		//window.location="#";
	},

	onBegin:function(){
		this.model={};
		var params=this.getRequest().getParams();
		this.articleID=params["ArticleID"];
		//alert(this.articleID);
		this.registerObserver();
		
		
	},
	onReloadPage: function()	{
		this.onBegin();
		this.run();
		//alert("aaa");
	},
	trim:function(s) {
		return s.replace(/^\s+/,"").replace(/\s+$/, "");
	},
	trimOfEditor:function(s){
		return s.replace(/^(&nbsp;)+/,"").replace(/(&nbsp;)+$/,"");
	},				
	convertHtmlDataToDisplay:function(s){
		return s.replace(/\\n/g,'').replace(/\\/g,'');
	},
	run:function(){
		this.getPortletPlaceholder().paintCanvas(this.render());
		var curID = "HungPDEditArticlePortlet-ArticleTextEditor";
		var sbj = SingletonFactory.getInstance(Subject);
		sbj.notifyEvent("TinyEditorInit",{id : curID, content: ""});
		sbj.notifyEvent("HungPDEditArticleTopicInputFetchAutoComplete",{});
		
					
		this.bindingArticleFromServer();					
	},
	onHungPDEditArticleTopicInputFetchAutoComplete:function(){
		//
		var addTopicInputBox=$("#"+this.name+"-txtTopicInput");//this.requestForEffectiveResource("txtTopicInput");
		//addTopicInputBox.val("sasas");
		//alert("aaa");
		var eventData={};
		eventData.selectCallback="HungPDEditArticleTopicInputSelect";
		eventData.autocompleteObject=addTopicInputBox;
		eventData.autocompleteSource="ajax/autocomplete-catchwords";
		var subject=SingletonFactory.getInstance(Subject);
		subject.notifyEvent("NeedAutocomplete",eventData);
	},
	onHungPDEditArticleTopicInputSelect:function(eventData){
	    var ui = eventData.ui;
		var i = 0;
    	var txt = ui.item.label;
    	var value = ui.item.id;   
    	//alert(txt);
		this.appendsTopic({'txt':txt,'value':value});
	},		
	bindingArticleFromServer:function(){
		var obj=this;
		var currentArticle={};
		//alert(obj.articleID);
		//var att=this.requestForEffectiveResource("txtArticleName").val("âsasa");
		this.onAjax('article','get-article-from-id',{'articleID':obj.articleID},'GET',{
			'onSuccess':function(ret){
				try{
					currentArticle.articleID=ret.details.id;
					currentArticle.articleTypeID=ret.details.typeID;
					currentArticle.articleTitle=ret.details.title;
					currentArticle.articleSummary=ret.details.summary;
					currentArticle.catchwordsID=ret.catchwordsID;
					currentArticle.catchwordsName=ret.catchwordsName;
					currentArticle.articleContent=ret.details.content;
					//var start=0;
					if(obj.topicValArray==undefined){
						obj.topicValArray=Array();
					}
					if(obj.topicTextArray==undefined){
						obj.topicTextArray=Array();
					}
					for(start=0;start<currentArticle.catchwordsID.length;start++){
						obj.topicValArray.push(currentArticle.catchwordsID[start]);
						obj.topicTextArray.push(currentArticle.catchwordsName[start]);
						obj.appendsTopicFirstTime({'txt':currentArticle.catchwordsName[start],'value':currentArticle.catchwordsID[start]});
					}
					obj.requestForEffectiveResource("txtArticleName").val(currentArticle.articleTitle);
					obj.requestForEffectiveResource("cbArticleType").val(currentArticle.articleTypeID);
					obj.requestForEffectiveResource("SummaryTextEditor").val(obj.convertHtmlDataToDisplay(currentArticle.articleSummary));
					var mceID = obj.name+"-ArticleTextEditor";
					var instance = obj.props.get("memcached.tinyeditor");
					var str=ret.details.content;
					instance[mceID].e.body.innerHTML=obj.convertHtmlDataToDisplay(str);//th
					//instance[mceID].e.body.innerHTML.replace(/\/g,"&lt;");
					//alert(str.replace(/\\/g,''));
					
				} catch(err){
					obj.topicValArray=Array();
					obj.topicTextArray=Array();
					currentArticle.articleID="";
					currentArticle.articleTitle=ret.details.title;
					currentArticle.articleSummary=ret.details.summary;
					currentArticle.articleContent=ret.details.content;
					alert(err);
				}
				
				//alert(currentArray);
				//alert(currentArticle.articleTitle);
			}
		});
		
	},
	appendsTopicFirstTime:function(eventData){
		var txt=eventData.txt;
		var value=eventData.value;
		//alert(value);
		var obj=this;
		for(start=0;start<this.topicTextArray.length;start++){
			if(obj.topicValArray[start]==value){
					break;
			}
		}
		if(start==this.topicTextArray.length){
			this.topicValArray.push(value);
			this.topicTextArray.push(txt);
			//return;
			
		}
		//this.topicValArray.push(value);
		//this.topicTextArray.push(txt);
		//alert(this.topicTextArray.length);
		var topicContainer=this.requestForEffectiveResource("TopicsContainer");
		var txtTopicInput=this.requestForEffectiveResource("txtTopicInput");
		var textToken=$("<label class=\"tokenContent\">"+txt+"</label>");			
		var span=$("<span>").addClass("edit_class").append(textToken);
		var a=$("<span>").addClass("btnStl").addClass("delToken").bind("click",function(event){
			var start=0;
			for(start=0;start<obj.topicValArray.length;start++){
				if(obj.topicValArray[start]==value){
					break;
				}
			}
			obj.topicValDeleteArray.push(obj.topicValArray[start]);
			alert("delete list: "+obj.topicValDeleteArray.length);
			obj.topicValArray.splice(start,1);
			obj.topicTextArray.splice(start,1);
			$(event.target).parent().remove();
		}).html("X").css("text-align","center").appendTo(span)	;
		topicContainer.append(span);
				
	},
	appendsTopic:function(eventData){
		var txt=eventData.txt;
		var value=eventData.value;
		//alert(this.topicTextArray.length);
		//alert(value);
		var obj=this;
		for(start=0;start<this.topicTextArray.length;start++){
			if(obj.topicValArray[start]==value){
					break;
			}
		}
		if(start==this.topicTextArray.length){
			this.topicValArray.push(value);
			this.topicTextArray.push(txt);
			this.topicValInsertArray.push(value);
			
		} else{
			return;
		}
		//alert(this.topicTextArray.length);
		//this.topicValArray.push(value);
		//this.topicTextArray.push(txt);
		//alert(this.topicTextArray.length);
		var topicContainer=this.requestForEffectiveResource("TopicsContainer");
		var txtTopicInput=this.requestForEffectiveResource("txtTopicInput");
		var textToken=$("<label class=\"tokenContent\">"+txt+"</label>");			
		var span=$("<span>").addClass("uiToken").append(textToken);
		var a=$("<span>").addClass("btnStl").addClass("delToken").bind("click",function(event){
			var start=0;
			for(start=0;start<obj.topicValArray.length;start++){
				if(obj.topicValArray[start]==value){
					break;
				}
			}
			obj.topicValDeleteArray.push(obj.topicValArray[start]);
			//alert("delete list: "+obj.topicValDeleteArray.length);
			obj.topicValArray.splice(start,1);
			obj.topicTextArray.splice(start,1);
			$(event.target).parent().remove();
		}).html("X").css("text-align","center").appendTo(span)	;
		topicContainer.append(span);	
		//alert("insert list: "+obj.topicValInsertArray.length);	
	},		
	onHungPDEditArticleSubmit:function(eventData){
		//alert("hungpd");
		//dau tien chung ta se validate truoc khi chay
		//ArticleError
		var errorArray=Array();
		var articleTitle=this.trim(this.requestForEffectiveResource("txtArticleName").val());
		var articleType=this.trim(this.requestForEffectiveResource("cbArticleType").val());		
		//alert(articleType);				
		var mceID = this.name+"-ArticleTextEditor";
		var instance = this.props.get("memcached.tinyeditor");
		var articleContent =this.trim(this.trimOfEditor(instance[mceID].e.body.innerHTML));//this.trimOfEditor(instance[mceID].e.body.innerHTML);
		var articleSummary=this.trim(this.requestForEffectiveResource("SummaryTextEditor").val());
		
		//alert(articleSummary);
		var topicLength=this.topicValArray.length;
	//	alert(articleTitle+" - "+articleContent+" - "+topicLength);
		if(articleTitle==""){
			errorArray.push("Hãy nhập tiêu đề bài viết!");
		}
		if(articleContent==""||articleContent=="<br>"){
			errorArray.push("Hãy nhập nội dung bài viết!");
		}			
		if(topicLength<=0){
			errorArray.push("Bài viết phải thuộc topic nào đó!");
		}
		if(errorArray.length>0){
			var errorList="<br/><font color=\"red\">";
			var start=0;
			for(start=0;start<errorArray.length;start++){
				errorList+=errorArray[start]+"<br/>";
				//alert(errorList);
			}
			errorList+="</font>";
			this.requestForEffectiveResource("ArticleError").html(errorList);
		} else{				
			//alert(selectedTopicsArray.length+" ");
			var conf=window.confirm('Bạn có chắc chắn muốn sửa');
			if(!conf){
				return;
			}
			var obj1=this;
			//alert(articleTitle);
			this.onAjax('article', 'edit-article', {'articleID':this.articleID,'title': articleTitle,'type':articleType,'summary':articleSummary, 'content': articleContent, 'catchwordsIDToDelete': obj1.topicValDeleteArray,'catchwordsIDToInsert': obj1.topicValInsertArray}, 'POST', 
			{'onSuccess': function(ret)	{
				obj1.topicValArray = Array();
				obj1.topicTextArray = Array();
				//alert("Thành công rồi!");
				var updateStatus=ret.message;
				//alert(ret.message);
				var sbj = SingletonFactory.getInstance(Subject);
				sbj.notifyEvent("NotifyGlobal", "Đã thay đổi bài viết thành công, bạn hãy đợi trong giây lát!");
				//window.alert('aaa');
				window.location='#!page/UserArticle';
			},
			'onFailure': function(message)	{
				var errorArray=Array();
				errorArray.push("Lỗi đã xảy ra khi đưa câu hỏi. Vui lòng check lại thông tin!");
				//	alert("Lỗi bực quá");
				var errorList="<br/><font color=\"red\">";
				var start=0;
				for(start=0;start<errorArray.length;start++){
					errorList+=errorArray[start]+"<br/>";
				//alert(errorList);
				}
			errorList+="</font>";
				obj1.requestForEffectiveResource("ArticleError").html(errorList);
				//obj.requestForEffectiveResource("QuestionError").html(obj.getLocalizedText("AskError"));
			}
		});
	};
	},
	onDeleteArticle:function(){
		var result=window.confirm('Bạn có chắc chắn xóa bài viết này?');
		if(result){
			
			this.onAjax('article', 'user-delete-article', {'articleID':this.articleID}, 'POST', 
			{'onSuccess': function(ret)	{
				window.alert('Cám ơn bạn. Nội dung bài viết đã được xóa');
				window.location='#!page/UserArticle';
			
			},
			onFailure:function(message){
			}});
		}
	},
	fetch:function(){			
	},
	onEnd: function(){
		this.unregisterObserver();
	}
}).implement(RenderInterface).implement(PortletInterface).implement(ObserverInterface).implement(AjaxInterface);
/*
 * HungPDInsertArticleCatchwordBoxPortlet: Popup hiện lên để nhập các topic cho bài viết
 */
ArticleInsertCatchwordBoxPortlet = Class.extend({
	init:function(){
		this.name="ArticleInsertCatchwordBoxPortlet";
		this.model={};
		this.selectedTopics = Array();
		this.selectedTopicsName=Array();
		this.usingFacebox=false;
		this.activeText="";
		this.activeValue="";
		//alert('asasasasa');
	},
	requestForEffectiveResource: function(targetName){
		if(this.usingFacebox){
			return $("#"+this.name+"-"+targetName);
		}else{
			return this._super.requestForEffectiveResource(targetName);
		}
	},	
	onBegin:function(){
		this.registerObserver();
	},
	onReloadPage:function(){
		this.onBegin();
		this.run();
	},
	onInsertArticleCatchwordsShow:function(eventData){
			//alert("Ha ha ha");
			this.showPortlet(eventData);
	},
	showPortlet:function(eventData){
		/*var loggedIn = SingletonFactory.getInstance(Application).getSystemProperties().get('user.login');
		if (loggedIn != 1)	{
			var subject = SingletonFactory.getInstance(Subject);
			subject.notifyEvent("NeedLogin", {type: 'InsertArticleCatchword', event: eventData});
		} else {
			this.doShowPortlet(eventData);
		}*/
		this.doShowPortlet(eventData);
	},
	doShowPortlet:function(eventData){
		
		/*
	
		 */
		this.usingFacebox=true;
		var app=SingletonFactory.getInstance(Application);
		var subject=SingletonFactory.getInstance(Subject);
		//this.model.optionMsg=$("#"+this.name+"-TextOptionalMessage").html();
		//this.model.optionalDetailMsg=$("#"+this.name+"-TextOptionalDetailMessage").html();
		//this.model.askMsg=$("#"+this.name+"-TextAskMessage").html();
		//alert("Ha ha ha");
		subject.notifyEvent('ShowPopup',{id:'HungPDInsertArticleCatchwordBox',title:'Hãy nhập topic',content:this.render()});
//		alert(this.selectedTopics.length+" a");
		if(this.selectedTopics!=undefined&&this.selectedTopics.length>0){
		var start=0;
		for(start=0;start<this.selectedTopics.length;start++){
		//	alert("asdasdasdassd");
			this.activeText=this.selectedTopicsName[start];
			this.activeValue=this.selectedTopics[start];
			this.appendTopic();
		};
			//appendT
		}

		var sbj = SingletonFactory.getInstance(Subject);
		sbj.notifyEvent("FetchArticleTopicsAutoComplete");			
		//alert("Ha ha ha");
	},	
	run:function(){
		//alert(this.selectedTopics.length+" a");
		this.getPortletPlaceHolder.paintCanvas(this.render());
	},

	onEnd:function(){
		//alert("Ko gọi nữa");
		this.unregisterObserver();
	},	
	onFetchArticleTopicsAutoComplete:function(){
		var eventData = {};
		//alert('sấ');		
		var addTopicInputBox = this.requestForEffectiveResource("InputBox"); 
		eventData.selectCallback="InsertArticleCatchwordSelect";//"AskNonTargetQuestionTopicSelect";
		eventData.autocompleteObject=addTopicInputBox;
		eventData.autocompleteSource="ajax/autocomplete-catchwords";
		//alert(addTopicInputBox.val());
		var subject=SingletonFactory.getInstance(Subject);
		subject.notifyEvent('NeedAutocomplete',eventData);
		//alert($(addTopicInputBox).val()+"sdds");
	},	
	onInsertArticleCatchwordSelect: function(eventData)	{
		//alert("ubuntu");
		var ui = eventData.ui;
		var i = 0;
		var txt = ui.item.label;
		var value = ui.item.id;	
		var subject = SingletonFactory.getInstance(Subject);
		subject.notifyEvent('InsertArticleCatchwordPortletAppend', {'txt': txt, 'value': value});
	},
	
	onInsertArticleCatchwordPortletAppend: function(eventData)	{
		var txt = eventData.txt;
		var value = eventData.value;
		var topicContainer = this.requestForEffectiveResource("AddTopicContainer");
		var addTopicInputBox = this.requestForEffectiveResource("InputBox");
		if (this.selectedTopics == undefined)
			this.selectedTopics = Array();
		if (this.selectedTopicsName == undefined)
			this.selectedTopicsName = Array();	
		for( i=0; i<this.selectedTopics.length;i++ ){
			if(this.selectedTopics[i] === value){
				return;
			}
		}
		var textToken = $("<label class='tokenContent'>"+txt+"</label>");
		
		this.selectedTopics.push(value);
		this.selectedTopicsName.push(txt);
		
		// UI ONLY
		var obj=this;
		var selectedTopics = this.selectedTopics;
		var selectedTopicsName = this.selectedTopicsName;
		var span = $("<span>").addClass("uiToken").append(textToken);
		var a = $("<span>").addClass("btnStl").addClass("delToken").bind("click",function(event){
				var start = 0;
				for( start=0; start<selectedTopics.length; start++ ){
					if(selectedTopics[start] === value){
						break;
					}
				}
				selectedTopics.splice(start, 1);
				selectedTopicsName.splice(start, 1);
				//obj.selectedTopicsName.pop(2);
				//alert($(event.target).parent());
				$(event.target).parent().remove();
			}).html("X").css("text-align","center").appendTo(span);
		topicContainer.append(span);
	},
	onInsertArticleCatchwordsButtonClick:function(eventData){
		//alert('I love you!');
		//var addTopicInputBox = this.requestForEffectiveResource('InputBox'); 
		//var term=this.requestForEffectiveResource('InputBox').val();
		//alert(term+" sdds");
		
		var subject=SingletonFactory.getInstance(Subject);
		subject.notifyEvent('AppendTopicsToPage',{topicValue:this.selectedTopics,topicText:this.selectedTopicsName});
		//this.selectedTopics=Array();
		//this.selectedTopicsName=Array();
	},
	appendTopic:function(){
		var txt =this.activeText;// eventData.txt;
		var value = this.activeValue;//eventData.value;
		var topicContainer = this.requestForEffectiveResource("AddTopicContainer");
		var addTopicInputBox = this.requestForEffectiveResource("InputBox");
		if (this.selectedTopics == undefined)
			this.selectedTopics = Array();
		if (this.selectedTopicsName == undefined)
			this.selectedTopicsName = Array();	
	
		var textToken = $("<label class='tokenContent'>"+txt+"</label>");
		//viec can o day chi la gan, ko can phai dua ra nua
		//this.selectedTopics.push(value);
		//this.selectedTopicsName.push(txt);
		
		// UI ONLY
		var selectedTopics = this.selectedTopics;
		var selectedTopicsName=this.selectedTopicsName;
		var span = $("<span>").addClass("uiToken").append(textToken);
		var a = $("<span>").addClass("btnStl").addClass("delToken").bind("click",function(event){
				var start = 0;
				for( start=0; start<selectedTopics.length; start++ ){
					if(selectedTopics[start] === value){
						break;
					}
				}
				selectedTopics.splice(start, 1);
				selectedTopicsName.splice(start, 1);
				//alert("da co");
				$(event.target).parent().remove();
			}).html("X").css("text-align","center").appendTo(span);
		topicContainer.append(span);
	},
	onInsertArticleCatchwordsButtonClick:function(eventData){
		//alert('I love you!');
		//var addTopicInputBox = this.requestForEffectiveResource('InputBox'); 
		//var term=this.requestForEffectiveResource('InputBox').val();
		//alert(term+" sdds");
		
		var subject=SingletonFactory.getInstance(Subject);
		subject.notifyEvent('AppendTopicsToPage',{topicValue:this.selectedTopics,topicText:this.selectedTopicsName});
	}
}).implement(RenderInterface).implement(PortletInterface).implement(ObserverInterface).implement(AjaxInterface);

/**
 * @author HungPDInsertArticlePortlet: Portlet để nhập bài viết mới
 */
ArticleInsertPortlet=Class.extend(
{
	init:function(){
		this.name="ArticleInsertPortlet";
		//this.usingFacebox=true;
		this.topicValArray=Array();
		this.topicTextArray=Array();
		//alert("ubuntu");
		//hai cai bien nay de phuc vu cho text editor
		this.app = SingletonFactory.getInstance(Application);
		this.props = this.app.getSystemProperties();
					
		//window.location="#";
	},
	/*requestForEffectiveResource: function(targetName){
		if(this.usingFacebox){
			return $("#"+this.name+"-"+targetName);
		}else{
			return this._super.requestForEffectiveResource(targetName);
		}
	},*/	
	onBegin:function(){
		//this.model={};
		this.registerObserver();
		
		
	},
	onReloadPage: function()	{
		this.onBegin();
		this.run();
		//alert("aaa");
	},
	onAppendTopicsToPage:function(eventData){
		//alert(eventData.id);
		var stringToAppend="<br/>";
		this.topicValArray=eventData.topicValue;
		this.topicTextArray=eventData.topicText;
		var start=0;
		for(start=0;start<this.topicValArray.length;start++){
			stringToAppend+=this.topicTextArray[start]+" "+this.topicValArray[start]+"<br/>";
		};
		stringToAppend+="<br/>";
		
		this.requestForEffectiveResource('TopicsContainer').html(stringToAppend);
		//var sub
		//alert($('HungPDInsertArticlePortlet-TopicsContainer'));
		
		var sbj=SingletonFactory.getInstance(Subject);
		
		sbj.notifyEvent("PopupRemove", {id: 'HungPDInsertArticleCatchwordBox'});
	},

	run:function(){
		//falert('sdsdsd');
		//chu y day la noi ma in cai portlet ra
		
		this.getPortletPlaceholder().paintCanvas(this.render());
		//sbj.notifyEvent("TinyEditorInit",{id:curID,content: ""});
		//alert('aaaaaaaa');
		var curID = "HungPDInsertArticlePortlet-ArticleTextEditor";
		var sbj = SingletonFactory.getInstance(Subject);
		sbj.notifyEvent("TinyEditorInit",{id : curID, content: ""});					
	},
	trim:function(s) {
		return s.replace(/^\s+/,"").replace(/\s+$/, "");
	},
	trimOfEditor:function(s){
		return s.replace(/^(&nbsp;)+/,"").replace(/(&nbsp;)+$/,"");
	},
	onHungPDInsertArticleSubmit:function(eventData){
		//alert("hungpd");
		//dau tien chung ta se validate truoc khi chay
		//ArticleError
		var errorArray=Array();
		var articleTitle=this.trim(this.requestForEffectiveResource("txtArticleName").val());
		var articleType=this.trim(this.requestForEffectiveResource("cbArticleType").val());		
		//alert(articleType);				
		var mceID = this.name+"-ArticleTextEditor";
		var instance = this.props.get("memcached.tinyeditor");
		var articleContent =this.trim(this.trimOfEditor(instance[mceID].e.body.innerHTML));//this.trimOfEditor(instance[mceID].e.body.innerHTML);
		var articleSummary=this.trim(this.requestForEffectiveResource("SummaryTextEditor").val());
		
		//alert(articleSummary);
		var topicLength=this.topicValArray.length;
	//	alert(articleTitle+" - "+articleContent+" - "+topicLength);
		if(articleTitle==""){
			errorArray.push("Hãy nhập tiêu đề bài viết!");
		}
		if(articleContent==""||articleContent=="<br>"){
			errorArray.push("Hãy nhập nội dung bài viết!");
		}			
		if(topicLength<=0){
			errorArray.push("Bài viết phải thuộc topic nào đó!");
		}
		if(errorArray.length>0){
			var errorList="<br/><font color=\"red\">";
			var start=0;
			for(start=0;start<errorArray.length;start++){
				errorList+=errorArray[start]+"<br/>";
				//alert(errorList);
			}
			errorList+="</font>";
			this.requestForEffectiveResource("ArticleError").html(errorList);
		} else{
			var selectedTopicsArray = null;
			if(this.topicValArray.length > 0){
				selectedTopicsArray = new Array();
			for( var i=0; i<this.topicValArray.length; i++ ){
			//	alert(this.topicValArray[i]);
				selectedTopicsArray.push({"catchword_id":this.topicValArray[i]}); 
			};
			//alert(selectedTopicsArray.length+" ");
			var obj1=this;
			this.onAjax('article', 'add-article', {'title': articleTitle,'type':articleType,'summary':articleSummary, 'content': articleContent, 'catch': selectedTopicsArray}, 'POST', 
			{'onSuccess': function(ret)	{
				obj1.topicValArray = Array();
				obj1.topicTextArray = Array();
				//alert("Thành công rồi!");
				var sbj = SingletonFactory.getInstance(Subject);
				sbj.notifyEvent("NotifyGlobal", "Đã nhập bài viết thành công, bạn hãy đợi trong giây lát!");
				window.location='#!page/Article';
			},
			'onFailure': function(message)	{
				var errorArray=Array();
				errorArray.push("Lỗi đã xảy ra khi đưa câu hỏi. Vui lòng check lại thông tin!");
				//	alert("Lỗi bực quá");
				var errorList="<br/><font color=\"red\">";
				var start=0;
				for(start=0;start<errorArray.length;start++){
					errorList+=errorArray[start]+"<br/>";
				//alert(errorList);
				}
			errorList+="</font>";
				obj1.requestForEffectiveResource("ArticleError").html(errorList);
				//obj.requestForEffectiveResource("QuestionError").html(obj.getLocalizedText("AskError"));
			}
			})
	};
			//alert("Nhập đúng rồi!");
		};
	},
	fetch:function(){			
	},
	onEnd: function(){
		this.unregisterObserver();
	}
}).implement(RenderInterface).implement(PortletInterface).implement(ObserverInterface).implement(AjaxInterface);
/**
 * @author Hung
 */
ArticleListPortlet = Class.extend({
	init : function() {
		this.name = "ArticleListPortlet";
	},
	
	onReloadPage: function() {
		this.run();
	},
	
	run: function() {
		var obj = this;
		var compact = this.getInitParameters().compact;
		var t = this.getRequest().getParam('t');
		var pageSize = undefined;
		if (compact == 1)	{
			pageSize = 5;
		}
		this.onAjax('article', 'list-articles', {type: t, pageSize: pageSize}, 'GET', {
			onSuccess: function(ret) {
				obj.model = {};
				obj.model.list = ret;
				obj.getPortletPlaceholder().paintCanvas(obj.render());

				if (compact == 1)	{
					$('.simple_tab').remove();
					obj.requestForEffectiveResource('Info').remove();
				} else {
					$('.simple_tab a').removeClass('active');
					if (t == undefined)	{
						t = 0;
					}
					$('.simple_tab a[type='+t+']').addClass('active');
				}
			}
		});
	}
}).implement(RenderInterface).implement(PortletInterface).implement(AjaxInterface);
ArticleSummaryPortlet = Class.extend({
	init: function()	{
		this.name = "ArticleSummaryPortlet";
	},
	
	onReloadPage: function()	{
		this.run();
	},
	
	run: function()	{
		var id = this.getRequest().getParam('aid');
		this.getPortletPlaceholder().paintCanvas(this.render());
		var obj = this;
		this.onAjax('article', 'get-summary', {id: id}, 'GET', {
			'onSuccess': function(ret)	{
				obj.requestForEffectiveResource('ContentPlaceholder').html(obj.renderView('ContentTmpl', ret));
			}
		});
	}
}).implement(PortletInterface).implement(AjaxInterface).implement(RenderInterface);
FeaturedArticlesPortlet = Class.extend({
	init: function()	{
		this.name = 'FeaturedArticlesPortlet';
		this.action = 'get-most-voted-articles';
	},
	
	run: function()	{
		var obj = this;
		this.getPortletPlaceholder().paintCanvas(this.render());
		this.onAjax('ajax', this.action, {}, 'GET', {
			'onSuccess': function(ret) {
				for(var i in ret)	{
					var maxLength = 75;
					if (ret[i].summary != undefined)	{
						var trimmed = ret[i].summary.trim().substr(0, maxLength - 3);
						var lastWordIndex = trimmed.lastIndexOf(' ');
						if (lastWordIndex != -1)	{
							trimmed = trimmed.substr(0, lastWordIndex);
						}
						ret[i].summary = trimmed + "...";
					}
				}
				obj.requestForEffectiveResource('ContentPlaceholder').html(obj.renderView('FeaturedArticles', {articles: ret}));
			}
		});
	}
}).implement(PortletInterface).implement(RenderInterface).implement(AjaxInterface);
LatestArticlesPortlet = FeaturedArticlesPortlet.extend({
	init: function()	{
		this.name = 'LatestArticlesPortlet';
		this.action = 'get-latest-articles';
	}
}).implement(PortletInterface).implement(RenderInterface).implement(AjaxInterface);
FeaturedNewsPortlet = Class.extend({
	init: function()	{
		this.name = "FeaturedNewsPortlet";
	},
	
	run: function()	{
		this.getPortletPlaceholder().drawToCanvas(this.render());
		this.fetch();
	},
	
	fetch: function() {
		var obj = this;
		this.onAjax('ajax','get-featured-news',{},'POST',{
			'onSuccess': function(ret){
				obj.requestForEffectiveResource('News').html(obj.renderView('NewsTmpl',{news:ret}));
			}
		});
	},
	
	onDynamicEditViewButtonClick: function(eventData)	{
		this.requestForEffectiveResource('News').find(".dynamic-edit-editable").hide();
	},
	
	onDynamicEditEditButtonClick: function(eventData)	{
		this.requestForEffectiveResource('News').find(".dynamic-edit-editable").show();
	}
}).implement(PortletInterface).implement(RenderInterface).implement(AjaxInterface);
NewsInsertPortlet = Class.extend({
	init: function()	{
		this.name = "NewsInsertPortlet";
	},
	
	onBegin: function()	{
		this.registerObserver();
	},
	
	run: function()	{
		this.getPortletPlaceholder().drawToCanvas(this.render());
		this.fetch();
	},
	
	fetch: function() {
		var obj = this;
		var id = this.getRequest().getParam('id');
		this.onAjax('ajax','get-partner-news',{'id':id},'POST', {
			'onSuccess': function(ret){
				var tblName = "partnerNews";
				var tmplType = 'NewsTmpl';
				// var x = {};
				// x.title="Điền tựa đề vào đây";
				// x.image="http://www.surfinginfuerteventura.com/wp-content/uploads/2011/06/advertise-here.gif";
				// x.content="Điền nội dung tóm tắt vào đây";
				// x.url="http://www.google.com.vn";
				// ret[ret.length] = x;
				var tmp = obj.requestForEffectiveResource('News');
				for (var i = 0; i<ret.length; i++){
					var tid = ret[i]['id'];
					ret[i].isNew=0;
					ret[i].tbl=tblName;
					obj.encapData(ret[i], tblName, tid, id);
					tmp.append(obj.renderView(tmplType,{news:ret[i]}));
				}
				obj.design(obj.requestForEffectiveResource('News'));
				var properties = SingletonFactory.getInstance(Application).getSystemProperties();
				var userID = properties.get('user.id',undefined);
				if (id === userID){
					obj.requestForEffectiveResource('News').find("span.dynamic-edit-selection").show();
				} else{
					obj.requestForEffectiveResource('News').find("span.dynamic-edit-selection").hide();
				}
				obj.requestForEffectiveResource('News').find(".dynamic-edit-editable").hide();
				
				//for hidden text suggestion
				var subject = SingletonFactory.getInstance(Subject);
				subject.notifyEvent('AttachFocusDetection', {'target': obj.requestForEffectiveResource('News').find("[name='title']"), 'defaultValue': 'Nhập vào tựa đề tin tức'});
				subject.notifyEvent('AttachFocusDetection', {'target': obj.requestForEffectiveResource('News').find("[name='content']"), 'defaultValue': 'Nhập vào tóm tắt tin tức'});
				subject.notifyEvent('AttachFocusDetection', {'target': obj.requestForEffectiveResource('News').find("[name='url']"), 'defaultValue': 'Nhập vào đường dẫn tới tin tức'});
				subject.notifyEvent('AttachFocusDetection', {'target': obj.requestForEffectiveResource('News').find("[name='title_new']"), 'defaultValue': 'Nhập vào tựa đề tin tức mới'});
			}
		});
	},
	
	onDynamicEditSaveButtonClick: function(eventData)	{
		var obj = this;
		var e = $(eventData.target).siblings("input");
		var key = e.attr("name");
		var id = e.attr("tid");
		var tbl = e.attr("tbl");
		var value = e.val();
		var json=[{'key':key, 'tbl':tbl, 'id':id, 'val': value}];
		this.onAjax('ajax', 'dynamic-update-profile', 
			{'data':json}
			, 'GET', 
			{onSuccess: function(ret)	{
				var form = e.parent(".dynamic-edit-form");
				var label = form.siblings(".dynamic-edit-content");
				label.find(".dynamic-edit-content-value").text($.trim(e.val()));
				label.show();
				form.hide();
				form.parents(".row").find("input").attr("tid",ret[0]);
				form.parents(".row").find("div.uploader").find("input").attr("value",ret[0]);
				form.parents(".row").find(".dynamic-edit-new-hide-first").show();
				// obj.design(obj.requestForEffectiveResource('News'));
			},
			onFailure: function(message)	{
				alert("Fail");
		}});
	},
	
	onDynamicEditCommitButtonClick: function(eventData)	{
		var obj = this;
		var json = [];
		var e = this.requestForEffectiveResource("News").find(".dynamic-edit-form:visible input");
		var i = 0;
		e.each(function() {
			var key = $(this).attr("name");
			var id = $(this).attr("tid");
			var tbl = $(this).attr("tbl");
			var value = $(this).val();
			json[i++]={'key':key, 'tbl':tbl, 'id':id, 'val': value};
		});
		
		this.onAjax('ajax', 'dynamic-edit-commit', 
			{'data':json}
			, 'GET', 
			{onSuccess: function(ret)	{
				alert("Success");
				e.each(function (){
					var form = $(this).parent(".dynamic-edit-form");
					var label = form.siblings(".dynamic-edit-content");
					label.find(".dynamic-edit-content-value").text($.trim(this.value));
					label.show();
					form.hide();
				});
			},
			onFailure: function(message)	{
				alert("Fail");
		}});
	},
	
	onChangeNewsImage: function(eventData)	{
		var target = eventData.e.target;
		var form = $(target).parent();
		var tmp = form.submit();
		var id = $(target).attr("tid");
		var obj = this;
		var getImageAjax = function ()	{
			obj.onAjax('ajax', 'get-news-image', 
				{'id':id}
				, 'GET', 
				{onSuccess: function(ret)	{
					form.parent().siblings("a").find("img").attr("src", ret);
				},
				onFailure: function(message)	{
					alert("Fail");
			}});
		};
		setTimeout(getImageAjax,200);
	},
	
	onDyanmicEditDeleteButtonClick: function(eventData)	{
		var ok = confirm("Bạn chắc muốn xóa chứ?'");
		if (ok)	{
			var obj = $(eventData.target);
			var row = obj.parents("div.row").hide();
			var tid = "";
			var tbl = "";
			row.find("input[tid]").each(function(){
				if(tid === "") {
					tid = $(this).attr("tid");
					tbl = $(this).attr("tbl");
				}
			});
			json = [];
			json[0]={'tbl':tbl, 'id':tid};
			this.onAjax('ajax', 'dynamic-delete-profile', 
			{'data':json}
			, 'GET', 
			{onSuccess: function(ret)	{
				alert("Xóa thành công!")
			},
			onFailure: function(message)	{
				alert("Có lỗi xảy ra khi xóa");
			}});
		}		
	},
	
	saveRows: function(e, func){
		var key = e.attr("name");
		if (key === "title_new"){
			key = "title";
		}
		var id = e.attr("tid");
		// var tbl = e.attr("tbl");
		// var fatherID = e.attr("fatherID");
		var fatherID = e.parents("[profileExtension]").attr("fatherID");
		var tbl = e.parents("[profileExtension]").attr("tbl");
		var value = e.val();
		var json=[{'key':key, 'tbl':tbl, 'id':id, 'val':value, 'fatherID':fatherID}];
		this.onAjax('ajax', 'dynamic-update-profile', 
			{'data':json}
			, 'GET', 
			{onSuccess: function(ret)	{
				var form = e.parent(".dynamic-edit-form");
				var label = form.siblings(".dynamic-edit-content");
				label.find(".dynamic-edit-content-value").text($.trim(e.val()));
				label.show();
				form.hide();
				form.parents(".row").find("input").attr("tid",ret[0]);
				form.parents(".row").find("div.uploader").find("input").attr("value",ret[0]);
				form.parents(".row").find(".dynamic-edit-new-hide-first").show();
				// obj.design(obj.requestForEffectiveResource('News'));
				if (func != null){
					func.call(this, ret[0]);
				}
			},
			onFailure: function(message)	{
				alert("Fail");
		}});
	},
	
	onAddNewItem: function(eventData){
		var tar = eventData.target;
		var e = eventData;
		var obj = this;
		if(e.which == 13){
			obj.saveRows($(e.target), function (id){
				var fid = $(e.target).parents("[profileExtension]").attr("fatherID");
				var lev = $(e.target).parents("[profileExtension]").attr("level");
				var tbl = $(e.target).parents("[profileExtension]").attr("tbl");
				var tm = $(e.target).parents("[profileExtension]").attr("tmpl");
				var ret = {title:e.target.value, isNew:1, fatherID:fid, level: lev, tbl: tbl, id: id};
				obj.encapData(ret, tbl, id, e.target.level);
				$(e.target).after(obj.renderView(tm, {news: ret}));
				obj.design($(e.target).parent());
				$(e.target).val("");
			});
		}
	},
	
	onDynamicEditAddButtonClick2: function(eventData)	{
		var obj = this;
		var oldLast = this.requestForEffectiveResource('News').find(".dynamic-edit-main .row:last");
		var newLast = oldLast.clone();
		oldLast.find(".dynamic-edit-new-hide-first").hide();
		oldLast = oldLast.show()[0];
		this.requestForEffectiveResource('News').find(".dynamic-edit-main").append(newLast);
		this.design($(oldLast));
	},
	
	onDynamicEditAddButtonClick: function(eventData)	{
		var obj = this;
		var profileExtensionName = "news";
		var tmplType = "NewsTmpl";
		var tmp = "[profileExtension='"+profileExtensionName+"']";
		var profileExtension = $(obj.requestForEffectiveResource('News')).find(tmp);
		tmp = {partner: {fatherID: {val: eventData.fatherID}, tbl: {val: eventData.tbl}, isNew: {val: 1}}};
		profileExtension.append(obj.renderView(tmplType, tmp));
		obj.design(obj.requestForEffectiveResource('News'));
	},
	
	onDynamicEditViewButtonClick: function(eventData)	{
		this.requestForEffectiveResource('News').find(".dynamic-edit-editable").hide();
	},
	
	onDynamicEditEditButtonClick: function(eventData)	{
		this.requestForEffectiveResource('News').find(".dynamic-edit-editable").show();
	},
	
	onEnd: function(){
		this.unregisterObserver();
	}
}).implement(PortletInterface).implement(RenderInterface).implement(ObserverInterface).implement(AjaxInterface).implement(InlineEditorInterface);
PartnerBasicInfoPortlet = Class.extend({
	init: function()	{
		this.name = "PartnerBasicInfoPortlet";
		this.registerObserver();
	},
	
	onBegin: function()	{
		this.model = {};
		this.registerObserver();
	},
	
	run: function()	{
		this.getPortletPlaceholder().drawToCanvas(this.render());
		this.fetch();
	},
	
	fetch: function()	{
		var obj = this;
		var id = this.getRequest().getParam('id');
		this.onAjax('ajax','get-partner-intro',{'id':id},'POST', {
			'onSuccess': function(ret){
				var tblName = "partner";
				var tmplType = 'IntroductionTmpl';
				var tid = ret['id'];
				obj.encapData(ret, tblName, tid, id);
				obj.requestForEffectiveResource('Introduction').html(obj.renderView(tmplType,{partner:ret}));
				obj.design(obj.requestForEffectiveResource('Introduction'));
				var properties = SingletonFactory.getInstance(Application).getSystemProperties();
				var userID = properties.get('user.id',undefined);
				if (id == userID){
					obj.requestForEffectiveResource('Introduction').find("span.dynamic-edit-selection").show();
				} else{
					obj.requestForEffectiveResource('Introduction').find("span.dynamic-edit-selection").hide();
				}
				obj.requestForEffectiveResource('Introduction').find(".dynamic-edit-editable").hide();
			}
		});
	},
	
	onDynamicEditViewButtonClick: function(eventData)	{
		this.requestForEffectiveResource('Introduction').find(".dynamic-edit-editable").hide();
	},
	
	onDynamicEditEditButtonClick: function(eventData)	{
		this.requestForEffectiveResource('Introduction').find(".dynamic-edit-editable").show();
	},
	
	onDynamicEditSaveButtonClick: function(eventData)	{
		var obj = this;
		var e = $(eventData.target).siblings("input");
		var key = e.attr("name");
		var id = e.attr("tid");
		var tbl = e.attr("tbl");
		var value = e.val();
		var json=[{'key':key, 'tbl':tbl, 'id':id, 'val': value}];
		this.onAjax('ajax', 'dynamic-update-profile', 
			{'data':json}
			, 'POST', 
			{onSuccess: function(ret)	{
				var form = e.parent(".dynamic-edit-form");
				var label = form.siblings(".dynamic-edit-content");
				label.find(".dynamic-edit-content-value").html($.trim(e.val()));
				label.show();
				form.hide();
				form.parents(".row").find("input").attr("tid",ret[0]);
				form.parents(".row").find(".dynamic-edit-new-hide-first").show();
			},
			onFailure: function(message)	{
				alert("Fail");
		}});
	},
	
	onEnd: function()	{
		this.unregisterObserver();
	}
}).implement(PortletInterface).implement(RenderInterface).implement(AjaxInterface).implement(InlineEditorInterface).implement(ObserverInterface);
PartnerLinkPortlet = Class.extend({
	init: function()	{
		this.name = "PartnerLinkPortlet";
	},
	
	onBegin: function()	{
		this.model = {};
	},

	run: function()	{
		this.getPortletPlaceholder().drawToCanvas(this.render());
	}
}).implement(PortletInterface).implement(RenderInterface);
PartnerProfileEditPortlet = Class.extend({
	
	init: function()	{
		this.name = "PartnerProfileEditPortlet";
	},
		
	onBegin: function()	{
		this.model = {};
		this.registerObserver();
	},
	
	onCancelUpdateProfile: function(target) {
		var p = $(target).parent();
		p.hide();
		p.siblings('.edit_content').show();
		p.siblings('.edit-note').show();
	},
	
	onUpdateProfile: function(data) {
		var obj = this;
		this.onAjax('user-ajax', 'update-profile', {field: data.field, value: data.value}, 'get', {
			onSuccess: function(ret) {
				var p = $(data.target).parent();
				if (data.show) return;
				p.hide();
				p.siblings('.edit_content').show();
				p.siblings('.edit-note').show();
				p.siblings('.edit_content').html(data.value);
			},
			onFailure: function(msg) {
				var subject = SingletonFactory.getInstance(Subject);
				subject.notifyEvent('NotifyError', msg);
			}
		});
	},

	run: function()	{
		var obj = this;
		this.onAjax('ajax', 'get-profile-info', {}, 'GET', {
			'onSuccess': function(ret)	{
				if (ret == undefined) ret = {};
				obj.model = {result: ret};
				obj.getPortletPlaceholder().paintCanvas(obj.render());
				$('input[value="'+ret.gender+'"]').attr('checked', 'checked');
				$('.edit-note').click(function() {
					$(this).siblings('.edit_content').hide();
					$(this).hide();
					$(this).siblings('.edit_placeholder').show();
				});
//				var tmplType = "partnerTmpl2";
//				var tblName = "";
//				if(ret.type === "person"){
//					tmplType = 'ProfileUserTmpl';
//					tblName = "person";
//				};
//				if (ret.type === "partner"){
//					tmplType = 'PartnerTmpl';
//					tblName = "partner";
//				};
//				var id = ret['primary_bind'];
//				obj.dynamicRender(ret, tblName, id, tmplType, 'profile', null, 1);
//				obj.design(obj.requestForEffectiveResource('Profile'));
//				var x =  obj.requestForEffectiveResource('Profile').find(".dynamic-edit-main .row:last");
//				x.show();
//				
//				//for hidden suggestion
//				var subject = SingletonFactory.getInstance(Subject);
//				subject.notifyEvent('AttachFocusDetection', {'target': obj.requestForEffectiveResource('Profile').find("[profileExtension='school']").children(".dynamic-edit-form-add-item"), 'defaultValue': 'Thêm trường mới rồi ấn enter'});
//				subject.notifyEvent('AttachFocusDetection', {'target': obj.requestForEffectiveResource('Profile').find("[profileExtension='class']").children(".dynamic-edit-form-add-item"), 'defaultValue': 'Thêm lớp mới rồi ấn enter'});
//				subject.notifyEvent('AttachFocusDetection', {'target': obj.requestForEffectiveResource('Profile').find("[profileExtension='project']").children(".dynamic-edit-form-add-item"), 'defaultValue': 'Thêm công ty mới rồi ấn enter'});
//				
//				//for date picker
//				// $('input.date_picker').datepicker( $.datepicker.regional[ "fr" ] );
//				$('input.date_picker').datepicker({
//					changeMonth: true,
//					changeYear: true,
//					yearRange: "-50:+0"
//				});
//				$('input.date_picker').datepicker( "option", "dateFormat", "dd/mm/yy");
			},
		});
	},
	
//	upperCaseFirstLetter: function(x){
//		return x.substring(0,1).toUpperCase() + x.substring(1);
//	},
//	
//	dynamicRender: function(ret, tblName, id, tmplType, profileExtensionName, fatherID, level){
//		obj = this;
//		obj.encapData(ret, tblName, id, level);
//		var tmp = "[profileExtension='"+profileExtensionName+"']:last";
//		var profileExtension = $(obj.requestForEffectiveResource('Profile')).find(tmp);
//		profileExtension.append(obj.renderView(tmplType, {partner: ret}));
//		for (var j in ret){
//			if ((typeof ret[j].val) === "object"){
//				var x = j;
//				var fatherID2 = ret[j].id;
//				ret[x] = ret[x]['val'];
//				for (var i in ret[x]){
//					var id2 = ret[x][i]['id'];
//					var tblName2 = "profileDetailed" + obj.upperCaseFirstLetter(x);
//					var ret2 = ret[x][i];
//					ret2.fatherID=fatherID2;
//					ret2.tbl=tblName2;
//					ret2.isNew=0;
//					ret2.level=level;
//					var tmplType2 = obj.upperCaseFirstLetter(x)+"Tmpl";
//					var profileExtensionName2 = x;
//					this.dynamicRender(ret2, tblName2, id2, tmplType2, profileExtensionName2, fatherID2, level+2);
//					// obj.encapData(ret[x][i], "profileDetailed" + obj.upperCaseFirstLetter(x) , id);
//					// var html = tmpl("MockupPartnerProfileEditPortlet-"+obj.upperCaseFirstLetter(x)+"Tmpl",{partner: ret[x][i]});
//					// $("#MockupPartnerProfileEditPortlet-"+obj.upperCaseFirstLetter(x)+"s").append(html);
//				}
//			}
//		}
//	},
//	
//	onDynamicEditSaveButtonClick: function(eventData)	{
//		var obj = this;
//		var e = $(eventData.target).siblings("input");
//		this.saveRows(e);
//		// var key = e.attr("name");
//		// var id = e.attr("tid");
//		// var tbl = e.attr("tbl");
//		// var fatherID = e.attr("fatherID");
//		// var value = e.val();
//		// var json=[{'key':key, 'tbl':tbl, 'id':id, 'val': value, 'fatherID': fatherID}];
//		// this.onAjax('ajax', 'dynamic-update-profile', 
//			// {'data':json}
//			// , 'GET', 
//			// {onSuccess: function(ret)	{
//				// var form = e.parent(".dynamic-edit-form");
//				// var label = form.siblings(".dynamic-edit-content");
//				// label.find(".dynamic-edit-content-value").text($.trim(e.val()));
//				// label.show();
//				// form.hide();
//				// form.parents(".row").find("input").attr("tid",ret[0]);
//				// form.parents(".row").find("div.uploader").find("input").attr("value",ret[0]);
//				// form.parents(".row").find(".dynamic-edit-new-hide-first").show();
//				// // obj.design(obj.requestForEffectiveResource('News'));
//			// },
//			// onFailure: function(message)	{
//				// alert("Fail");
//		// }});
//	},
//	
//	saveRows: function(e, func){
//		var key = e.attr("name");
//		var id = e.attr("tid");
//		// var tbl = e.attr("tbl");
//		// var fatherID = e.attr("fatherID");
//		var fatherID = e.parents("[profileExtension]").attr("fatherID");
//		var tbl = e.parents("[profileExtension]").attr("tbl");
//		var value = e.val();
//		var json=[{'key':key, 'tbl':tbl, 'id':id, 'val':value, 'fatherID':fatherID}];
//		this.onAjax('ajax', 'dynamic-update-profile', 
//			{'data':json}
//			, 'GET', 
//			{onSuccess: function(ret)	{
//				var form = e.parent(".dynamic-edit-form");
//				var label = form.siblings(".dynamic-edit-content");
//				label.find(".dynamic-edit-content-value").text($.trim(e.val()));
//				label.show();
//				form.hide();
//				form.parents(".row").find("input").attr("tid",ret[0]);
//				form.parents(".row").find("div.uploader").find("input").attr("value",ret[0]);
//				form.parents(".row").find(".dynamic-edit-new-hide-first").show();
//				// obj.design(obj.requestForEffectiveResource('News'));
//				if (func != null){
//					func.call(this, ret[0]);
//				}
//			},
//			onFailure: function(message)	{
//				alert("Fail");
//		}});
//	},
//	
//	onDynamicEditAddButtonClick: function(eventData)	{
//		var obj = this;
//		var profileExtensionName = "school";
//		var tmplType = "ClassTmpl";
//		var tmp = "[profileExtension='"+profileExtensionName+"']:last";
//		var profileExtension = $(obj.requestForEffectiveResource('Profile')).find(tmp);
//		tmp = {partner: {fatherID: {val: eventData.fatherID}, tbl: {val: eventData.tbl}, isNew: {val: 1}}};
//		profileExtension.append(obj.renderView(tmplType, tmp));
//		obj.design(obj.requestForEffectiveResource('Profile'));
//	},
//	
//	onMockupUpdateProfileButtonClick: function(eventData)	{
//		var obj = this;
//		var json = [];
//		var e = this.requestForEffectiveResource('FormMain');
//		var i = 0;
//		e.find("span.edit-profile-form:visible input").each(function() {
//			var key = $(this).attr("name");
//			var id = $(this).attr("tid");
//			var tbl = $(this).attr("tbl");
//			var value = $(this).val();
//			json[i++]={'key':key, 'tbl':tbl, 'id':id, 'val': value};
//		});
//		
//		this.onAjax('ajax', 'dynamic-update-profile', 
//			{'data':json}
//			, 'GET', 
//			{onSuccess: function(ret)	{
//				alert("Success");
//				var lb = obj.requestForEffectiveResource('FormMain').find("span.edit-profile-label");
//				var form = obj.requestForEffectiveResource('FormMain').find("span.edit-profile-form");
//				var tmp = form.find("input:visible").each(function (){
//					var lb = $(this).parent("span.edit-profile-form").siblings("span.edit-profile-label");
//					var val = lb.find("span.edit-profile-label-value");
//					val.text($.trim(this.value));
//					lb.show();
//				});
//				form.hide();
//			},
//			onFailure: function(message)	{
//				alert("Fail");
//		}});
//			
//	},
//	
//	addNewItem: function(tar){
//		var obj = this;
//		tar.find(".dynamic-edit-form-add-item").keypress(function(e){
//			if(e.which == 13){
//				obj.saveRows($(e.target), function (id){
//					var fid = $(e.target).attr("fatherID");
//					var lev = $(e.target).attr("level");
//					var tbl = $(e.target).attr("tbl");
//					var tm = $(e.target).attr("tmpl");
//					var ret = {name:e.target.value, isNew:1, fatherID:fid, level: lev, tbl: tbl, id: id};
//					obj.encapData(ret, tbl, id, e.target.level);
//					$(e.target).after(obj.renderView(tm, {partner: ret}));
//					obj.design($(e.target).parent());
//					$(e.target).val("");
//				});
//			}
//		});
//	},
//	
//	onDyanmicEditDeleteButtonClick: function(eventData)	{
//		var ok = confirm("Bạn chắc muốn xóa chứ?'");
//		if (ok)	{
//			var obj = $(eventData.target);
//			var row = obj.parents(".dynamic-edit-head-item").parent(".dynamic-edit-main").hide();
//			console.log(row);
//			var tid = "";
//			var tbl = "";
//			row.find("input[tid]").each(function(){
//				if(tid === "") {
//					tid = $(this).attr("tid");
//					tbl = $(this).attr("tbl");
//				}
//			});
//			json = [];
//			json[0]={'tbl':tbl, 'id':tid};
//			this.onAjax('ajax', 'dynamic-delete-profile', 
//			{'data':json}
//			, 'GET', 
//			{onSuccess: function(ret)	{
//				alert("Xóa thành công!")
//			},
//			onFailure: function(message)	{
//				alert("Có lỗi xảy ra khi xóa");
//			}});
//		}		
//	},
//	
//	onAddNewItem: function(eventData){
//		var tar = eventData.target;
//		var e = eventData;
//		var obj = this;
//		if(e.which == 13){
//			obj.saveRows($(e.target), function (id){
//				var fid = $(e.target).parents("[profileExtension]").attr("fatherID");
//				var lev = $(e.target).parents("[profileExtension]").attr("level");
//				var tbl = $(e.target).parents("[profileExtension]").attr("tbl");
//				var tm = $(e.target).parents("[profileExtension]").attr("tmpl");
//				var ret = {name:e.target.value, isNew:1, fatherID:fid, level: lev, tbl: tbl, id: id};
//				obj.encapData(ret, tbl, id, e.target.level);
//				$(e.target).after(obj.renderView(tm, {partner: ret}));
//				obj.design($(e.target).parent());
//				$(e.target).val("");
//			});
//		}
//	},
	
	onEnd: function()	{
		this.unregisterObserver();
	}

}).implement(PortletInterface).implement(RenderInterface).implement(ObserverInterface).implement(AjaxInterface).implement(InlineEditorInterface);
PartnerProfilePortlet = Class.extend({
	init: function()	{
		this.name = "PartnerProfilePortlet";
	},
	
	onBegin: function()	{
		this.model = {};
	},

	run: function()	{
		this.getPortletPlaceholder().drawToCanvas(this.render());
		this.fetch();
	},
	
	fetch: function()	{
		var obj = this;
		var id = this.getRequest().getParam('id');
		this.onAjax('ajax', 'get-profile-info', {'id': id}, 'GET', {
			'onSuccess': function(ret)	{
				obj.requestForEffectiveResource('HeaderInfo').html(obj.renderView('HeaderInfoTmpl', {partner: ret}));
			},
		});
	},
	
	onEnd: function()	{
	}

}).implement(PortletInterface).implement(RenderInterface).implement(AjaxInterface);
/**
 * @author DUNGBK
 */
PartnersPortlet = Class.extend({
	init: function()	{
		this.name = "PartnersPortlet";
	},
	
	onBegin: function()	{
		this.model = {};
	},

	run: function()	{
		this.getPortletPlaceholder().drawToCanvas(this.render());
	}
}).implement(PortletInterface).implement(RenderInterface);
ProfileViewPortlet = Class.extend({
	init: function()	{
		this.name = "ProfileViewPortlet";
	},
		
	onBegin: function()	{
		this.model = {};
		this.registerObserver();
	},

	run: function()	{
		var obj = this;
		var id = this.getRequest().getParam('id');
		this.onAjax('ajax', 'get-profile-info', {id: id}, 'GET', {
			'onSuccess': function(ret)	{
				obj.model = {result: ret};
				obj.getPortletPlaceholder().paintCanvas(obj.render());
			},
		});
	},
	
//	upperCaseFirstLetter: function(x){
//		return x.substring(0,1).toUpperCase() + x.substring(1);
//	},
//	
//	dynamicRender: function(ret, tblName, id, tmplType, profileExtensionName, fatherID, level){
//		obj = this;
//		obj.encapData(ret, tblName, id, level);
//		var tmp = "[profileExtension='"+profileExtensionName+"']:last";
//		var profileExtension = $(obj.requestForEffectiveResource('Profile')).find(tmp);
//		profileExtension.append(obj.renderView(tmplType, {partner: ret}));
//		for (var j in ret){
//			if ((typeof ret[j].val) === "object"){
//				var x = j;
//				var fatherID2 = ret[j].id;
//				ret[x] = ret[x]['val'];
//				for (var i in ret[x]){
//					var id2 = ret[x][i]['id'];
//					var tblName2 = "profileDetailed" + obj.upperCaseFirstLetter(x);
//					var ret2 = ret[x][i];
//					ret2.fatherID=fatherID2;
//					ret2.tbl=tblName2;
//					ret2.isNew=0;
//					ret2.level=level;
//					var tmplType2 = obj.upperCaseFirstLetter(x)+"Tmpl";
//					var profileExtensionName2 = x;
//					this.dynamicRender(ret2, tblName2, id2, tmplType2, profileExtensionName2, fatherID2, level+2);
//					// obj.encapData(ret[x][i], "profileDetailed" + obj.upperCaseFirstLetter(x) , id);
//					// var html = tmpl("MockupPartnerProfileEditPortlet-"+obj.upperCaseFirstLetter(x)+"Tmpl",{partner: ret[x][i]});
//					// $("#MockupPartnerProfileEditPortlet-"+obj.upperCaseFirstLetter(x)+"s").append(html);
//				}
//			}
//		}
//	},
	
	onEnd: function()	{
		this.unregisterObserver();
	}
}).implement(PortletInterface).implement(RenderInterface).implement(ObserverInterface).implement(AjaxInterface).implement(InlineEditorInterface);
BestProfilesPortlet = Class.extend({
	init : function() {
		this.name = "BestProfilesPortlet";
		this.model = {};
		this.defaultResultNo = 5;
	},
	
	onBegin: function(){
		this.registerObserver();
		this.cache = new Array();
		this.expertiseID = this.getRequest().getParam('id');
	},
	
	// done
	run : function() {
		var _this = this;
		this.getPortletPlaceholder().paintCanvas(this.render());
		var fl1 = 'expertise_name_' + this.expertiseID;
		var fl2 = 'expert_rank_position_' + this.expertiseID;
		var fl3 = 'expert_rank_percentage_' + this.expertiseID;
		var fl4 = 'expert_rank_name_' + this.expertiseID;
		var fl5 = 'interest_name_' + this.expertiseID;
		var solrRoot = SingletonFactory.getInstance(Application).getSystemProperties().get('host.solr');
		var url = solrRoot+"/person/hardcore?wt=json&version=2.2&echoParams=NONE";
		var fl = 'profile_id,full_name,avatar,' + fl1 + "," + fl2 + "," + fl3 + "," + fl4 + "," + fl5;
		$.getJSON(url, {'rows':5,'q':this.expertiseID,'fl':fl}, function(ret){
			ret = ret.response.docs;
			_this.cache["bestprofilepage"] = 0;
			_this.cache["bestprofiles"] = new Array();
			if(ret.length != 0){
				_this.cache["bestprofiles"] = ret;
				_this.fetchData(ret, 0, _this.defaultResultNo);
			} else {
				_this.requestForEffectiveResource('TopContent').find(".top-userpro").append("<div class='italic'>Chưa có xếp hạng</div>");
			}
		});
	},
	
	fetchData: function(ret,start,stop){
		this.requestForEffectiveResource('TopContent').find(".top-userpro").empty();
		var isRanked = true;
		for( var i = start; i< stop; i++){
			if(ret[i] == undefined){
				continue;
			}
			var objParam = {};
			objParam.avatar = ret[i].avatar ;
			objParam.name = ret[i].full_name ;
			var expertiseName = 'expertise_name_' + this.expertiseID;
			var expertRankName = 'expert_rank_name_' + this.expertiseID;
			var interestName = 'interest_name_' + this.expertiseID;
			objParam.topic = ret[i][expertiseName] || ret[i][expertRankName] || ret[i][interestName];
			var expertiseRank = 'expert_rank_position_' + this.expertiseID;
			if(ret[i][expertiseRank] != undefined){
//						objParam.rank = ret[i][expertiseRank];
				objParam.rank = (i+1);
			} else {
				objParam.rank = undefined;
				isRanked = false;
			}
			objParam.id = ret[i].profile_id;
			var obj = {};
			var expertRankPercentage = 'expert_rank_percentage_' + this.expertiseID;
			obj.er = ret[i][expertRankPercentage] || 0;
			obj.total = 1000;
			objParam.tips = tmpl("ExpertiseRankDescription",obj);
			var data = tmpl("BestProfilesPortletItem",objParam);
			this.requestForEffectiveResource('TopContent').find(".top-userpro").append(data);
		}
		if(!isRanked){
			this.requestForEffectiveResource('TopContent').find(".top-userpro").prepend("<div class=\"italic\">Chưa có xếp hạng</div>");
		}
		var sbj = SingletonFactory.getInstance(Subject);
		sbj.notifyEvent("HtmlUpdated");
		
	},
	
	onBestProfilesNext: function(){
		this.cache["bestprofilepage"] ++;
		if(this.cache["bestprofilepage"] * this.defaultResultNo >= this.cache["bestprofiles"].length){
			this.cache["bestprofilepage"] --;
			return;
		}
		var start = this.cache["bestprofilepage"] * this.defaultResultNo;
		var stop = this.cache["bestprofilepage"] * this.defaultResultNo + this.defaultResultNo;
		this.fetchData(this.cache["bestprofiles"], start, stop);
	},
	
	onBestProfilesPrevious: function(){
		if(this.cache["bestprofilepage"] == 0){
			return;
		}
		this.cache["bestprofilepage"] --;
		var start = this.cache["bestprofilepage"] * this.defaultResultNo;
		var stop = this.cache["bestprofilepage"] * this.defaultResultNo + this.defaultResultNo;
		this.fetchData(this.cache["bestprofiles"], start, stop);
	},
	
	onReloadPage: function(){
		this.onBegin();
		this.run();
	},
	
	onEnd: function()	{
		this.unregisterObserver();
	}
}).implement(PortletInterface).implement(RenderInterface).implement(ObserverInterface).implement(AjaxInterface);
BriefInfoPortlet = Class.extend({
	init: function()	{
		this.name = "BriefInfoPortlet";
	},
	
	onReloadPage: function()	{
		this.run();
	},
	
	run: function()	{
		this.model = {};
		var root = SingletonFactory.getInstance(Application).getSystemProperties().get('host.root');
		var obj = this;
		var props = SingletonFactory.getInstance(Application).getSystemProperties();
		var id = this.getRequest().getParam('id');
		this.onAjax('user-ajax', 'get-brief-info', {'id': id}, 'GET', {
			'onSuccess': function(ret)	{
				// basic
				var avatar = ret.avatar;
				obj.model.page = obj.getRequest().getParam('page');
				obj.model.id = id ? id: props.get('user.id');
				obj.model.name = ret.name;
				obj.model.avatar = avatar;
				
				// statistic
				obj.model.answerCount = ret.answerCount;
				obj.model.questionCount = ret.questionCount;
				obj.model.score = ret.score;
				if (ret.isExpert == 0)	{
					if (ret.score < 200)	{
						obj.model.titleType = 0;
						obj.model.title = "Thành viên thường";
					} else if (ret.score < 600) {
						obj.model.titleType = 1;
						obj.model.title = "Thành viên tích cực";
					} else {
						obj.model.titleType = 2;
						obj.model.title = "Thành viên uy tín";
					}
				} else {
					obj.model.titleType = 3;
					obj.model.title = "Chuyên gia về "+ret.expertField;
				}
				
				// interests
				obj.model.interestTitle = "Lĩnh vực quan tâm";
				obj.model.interestContexts = ret.interests;
				
				// catches
				obj.model.expertiseTitle = "Kinh nghiệm";
				obj.model.expertiseContexts = ret.catches;
				
				obj.getPortletPlaceholder().paintCanvas(obj.render());
			}
		});
	}
}).implement(PortletInterface).implement(RenderInterface).implement(AjaxInterface);
ExpertiseAdderPortlet = Class.extend({
	init: function()	{
		this.name = "ExpertiseAdderPortlet";
	},
	
	onBegin: function()	{
		this.registerObserver();
	},
	
	onSubmitExpertiseAdderButtonClick: function()	{
		var subject = SingletonFactory.getInstance(Subject);
		subject.notifyEvent('SubmitExpertiseForward', {callback: function()	{
			subject.notifyEvent('NotifyGlobal', 'Đã thêm thành công');
		}, namespace: this.name});
	},
	
	run: function()	{
		this.getPortletPlaceholder().paintCanvas(this.render());
		var subject = SingletonFactory.getInstance(Subject);
		subject.notifyEvent('RenderExpertiseEditor', {placeholder:this.requestForEffectiveResource('ExpertisePlaceholder'), namespace: this.name});
	},
	
	onEnd: function()	{
		this.unregisterObserver();
	}
}).implement(PortletInterface).implement(RenderInterface).implement(ObserverInterface);
ExpertisePortlet = Class.extend({
	init: function()	{
		this.name = "ExpertisePortlet";
	},
	
	onBegin: function()	{
		this.model = {};
		this.registerObserver();
	},
	
	onEnd: function()	{
		this.unregisterObserver();
	},
	
	onReloadPage: function()	{
		this.run();
	},
	
	onExpertiseChanged: function()	{
		this.useCache = false;
		this.run();
		this.useCache = true;
	},
	
	run: function()	{
		var root = SingletonFactory.getInstance(Application).getSystemProperties().get('host.root');
		var obj = this;
		var id = this.getRequest().getParam('id');
		this.onAjax('user-ajax', 'get-all-expertises', {'id': id}, 'GET', 
			{'onSuccess': function(ret)	{
				var empty = true;
				for (var i in ret)	{
					empty = false;
					break;
				}
	
				obj.model.empty = empty;
				obj.model.expertiseContexts = ret;
				obj.getPortletPlaceholder().paintCanvas(obj.render());
			}}, this.useCache, 300000);
	}
}).implement(PortletInterface).implement(RenderInterface).implement(AjaxInterface).implement(ObserverInterface);
ExpertiseEditPortlet = ExpertisePortlet.extend({
	init: function()	{
		this.name = "ExpertiseEditPortlet";
	}
}).implement(PortletInterface).implement(RenderInterface).implement(AjaxInterface);
ExpertsPortlet = Class.extend({
	init: function()	{
		this.name = "ExpertsPortlet";
		this.pos = 0;
	},
	
	onBegin: function()	{
		this.model = {};
	},
	
	run: function()	{
		var obj = this;
		this.onAjax('ajax', 'get-experts', {}, 'GET', {
			'onSuccess': function(ret)	{
				obj.model = {users: ret};
				obj.getPortletPlaceholder().paintCanvas(obj.render());
				obj.startInterval(6000, obj.slideUsers);
			}
		});
	},
	
	slideUsers: function() {
		var e = this.requestForEffectiveResource('Experts');
		var total = e.children().length;
		var w = e.find('.box_user').width();
		this.pos -= 3;
		if (-this.pos >= total)
			this.pos = 0;
		e.animate({'left': this.pos*w}, 1500);
	},
	
	onEnd: function() {
		this.stopInterval();
	}
}).implement(PortletInterface).implement(RenderInterface).implement(AjaxInterface).implement(IntervalTimerInterface);
FeaturedProfilesPortlet = Class.extend({
	init: function()	{
		this.name = "FeaturedProfilesPortlet";
	},
	
	run: function()	{
		var obj = this;
		var solrRoot = SingletonFactory.getInstance(Application).getSystemProperties().get('host.solr');
		var url = solrRoot+"/person/best?wt=json&version=2.2&echoParams=NONE";
		$.getJSON(url, {
			'start':0, 'rows':7
		}, function(ret)	{
				var docs = ret.response.docs;
				obj.model = {};
				obj.model.users = Array();
				//shuffle
				var shuffled = Array();
				for(var i=0;i<2;i++)	{
					var rand = Math.floor(Math.random()*docs.length);
					shuffled.push(docs[rand]);
					docs.splice(rand, 1);
				}
				
				for(var i=0;i<shuffled.length;i++)	{
					var expertises = Array();
					if (shuffled[i].expertise != undefined)	{
						for(var j=0;j<shuffled[i].expertise.length && j<2;j++)	{
							expertises.push(shuffled[i].expertise[j]);
						}
					}
					expertises = expertises.join(', ');
					if (expertises.length > 20)
						expertises = expertises.substr(0, 17)+'...';
					obj.model.users.push({id: shuffled[i].profile_id, name:shuffled[i].full_name, expertise:expertises});
				}
				obj.getPortletPlaceholder().paintCanvas(obj.render());
			});
	}
}).implement(PortletInterface).implement(RenderInterface).implement(AjaxInterface);
InterestAdderPortlet = Class.extend({
	init: function()	{
		this.name = "InterestAdderPortlet";
	},
	
	onBegin: function()	{
		this.registerObserver();
	},
	
	onSubmitInterestAdderButtonClick: function()	{
		var subject = SingletonFactory.getInstance(Subject);
		subject.notifyEvent('SubmitInterestForward', {callback: function()	{
			subject.notifyEvent('NotifyGlobal', 'Đã thêm thành công');
		}, namespace: this.name});
	},
	
	run: function()	{
		this.getPortletPlaceholder().paintCanvas(this.render());
		var subject = SingletonFactory.getInstance(Subject);
		subject.notifyEvent('RenderInterestEditor', {placeholder:this.requestForEffectiveResource('ExpertisePlaceholder'), namespace: this.name});
	},
	
	onEnd: function()	{
		this.unregisterObserver();
	}
}).implement(PortletInterface).implement(RenderInterface).implement(ObserverInterface);
InterestedAreaPortlet = Class.extend({
	init: function()	{
		this.name = "InterestedAreaPortlet";
		this.useCache = true;
	},
	
	onBegin: function()	{
		this.model = {};
		this.registerObserver();
	},
	
	onEnd: function()	{
		this.unregisterObserver();
	},
	
	onInterestedAreaChanged: function()	{
		this.useCache = false;
		this.run();
		this.useCache = true;
	},
	
	run: function()	{
		var root = SingletonFactory.getInstance(Application).getSystemProperties().get('host.root');
		var obj = this;
		var id = this.getRequest().getParam('id');
		this.onAjax('user-ajax', 'get-all-interests', {'id': id}, 'GET', 
				{'onSuccess': function(ret)	{
					var empty = true;
					for(var i in ret)	{
						empty = false;
						break;
					}
					obj.model.empty = empty;
					obj.model.interestContexts = ret;
					obj.getPortletPlaceholder().paintCanvas(obj.render());
				}}, this.useCache, 300000);
	}
}).implement(PortletInterface).implement(RenderInterface).implement(AjaxInterface).implement(ObserverInterface);
InterestedAreaEditPortlet = InterestedAreaPortlet.extend({
	init: function()	{
		this.name = "InterestedAreaEditPortlet";
	}
}).implement(PortletInterface).implement(RenderInterface).implement(AjaxInterface);
ProfileFinishPortlet = Class.extend({
	init: function()	{
		this.name = "ProfileFinishPortlet";
	},
	
	onReloadPage: function() {
		this.run();
	},
	
	run: function()	{
		var obj = this;
		this.onAjax('user-ajax', 'check-finish-profile', {}, 'GET', {
			'onSuccess': function(ret)	{
				obj.model = {};
				var inc = 20;
				obj.model.finish = inc;
				obj.model.msgs = Array();
				if(ret.avatar != false) obj.model.finish += inc;
				else obj.model.msgs.push('<a href="#!page/UserAvatarEdit">Bạn chưa cập nhật hình đại diện?</a>');
				if(ret.catches != false) obj.model.finish += inc;
				else obj.model.msgs.push('<a href="#!page/UserExpertiseEdit">Bạn chưa cập nhật kinh nghiệm?</a>');
				if(ret.interest != false) obj.model.finish += inc;
				else obj.model.msgs.push('<a href="#!page/UserInterestEdit">Bạn chưa cập nhật lĩnh vực quan tâm?</a>');
				if(ret.question != false) obj.model.finish += inc;
				else obj.model.msgs.push('<a onclick=\'generateEvent("MakeNewQuestion", {})\'>Bạn chưa đặt câu hỏi nào?</a>');
				if (obj.model.finish < 100)
					obj.getPortletPlaceholder().paintCanvas(obj.render());
			}
		});
	}
}).implement(PortletInterface).implement(RenderInterface).implement(AjaxInterface);
AnswerPortlet = Class.extend({
	init : function() {
		this.name = "AnswerPortlet";
		this.model = {};
		this.question = null;
		this.topics = null;
		this.topicsQuestion = null;
		this.mce = $("");
		this.answers = null;
		this.questionID = null;
		this.needMCE = true;
		this.answerNum = 0;
		this.root = SingletonFactory.getInstance(Application).getSystemProperties().get("host.root");
		this.uid = SingletonFactory.getInstance(Application).getSystemProperties().get("user.id");
		this.quid = "";
	},

	onBegin : function() {
		this.registerObserver();
		this.model.qvoteup = "...";
		this.model.qvotedown = "...";
		this.model.avaiTopics = {};
		this.model.topics = {};
		this.model.mce = {};
		this.model.children = {};
	},
	
	getQuestionID: function(){
		var request = SingletonFactory.getInstance(Page).getRequest();
		var params = request.getParams();
		this.questionID = params['qid'];
		if(this.questionID == null || this.questionID == undefined){
			var subject = SingletonFactory.getInstance(Subject);
			var request = new Request("ErrorPage","donganh",{"code":"888", "msg":"Lỗi","content":"Câu hỏi không tồn tại trong hệ thống. Mong bạn thử lại"}); 
			subject.notifyEvent('RequestRoute', request);
		}
	},
	
	getAjax: function(){
		var curPlt = this;
		this.onAjax("question", "get-question-detail", {qid: this.questionID}, "GET", {
			onSuccess: function(ret) { 
				curPlt.question = ret;
				
				var owner = ret.userId;
				curPlt.ownerAvatar = ret.avatar;
				curPlt.questionOwner = owner;
				curPlt.buildQuestion();
				curPlt.getPortletPlaceholder().paintCanvas(curPlt.render());
				curPlt.requestForEffectiveResource('QVote').html("+"+ret.vote);
				curPlt.onAjax("question", "is-bookmarked", {id: curPlt.questionID}, "get", {
					onSuccess: function(ret) {
						if (ret)	{
							curPlt.requestForEffectiveResource("Bookmark").addClass('active');
						}
					}
				});
				
				var sbj = SingletonFactory.getInstance(Subject);
				sbj.notifyEvent('QuestionBuilt', {id: curPlt.questionID, userID: curPlt.questionOwner});
				
				var props = SingletonFactory.getInstance(Application).getSystemProperties();
				var role = 'default';
				if (props.get('user.login') == 1)	{
					role = props.get('user.role');
				}
				if (curPlt.questionOwner != curPlt.uid && (role == 'user' || role == 'default'))	{
					curPlt.requestForEffectiveResource('Question').find('.owner_fn').hide();
				}
				curPlt.getAjaxTopicQuestion();
			},
			onFailure: function(msg)	{
				var subject = SingletonFactory.getInstance(Subject);
				var request = new Request("ErrorPage","",{"code":"888", "msg":"Lỗi","content":"Câu hỏi không tồn tại trong hệ thống. Mong bạn thử lại"}, ["content"]); 
				subject.notifyEvent('RequestRoute', request);
				return;
			}
		});
	},
	
	onSystemPropertyChanged: function(eventData)	{
		if (eventData == 'user.login')	{
			var logged = SingletonFactory.getInstance(Application).getSystemProperties().get('user.login');
			if (logged == 1)	{
				var sbj = SingletonFactory.getInstance(Subject);
				sbj.notifyEvent('QuestionBuilt', {id: this.questionID, userID: this.questionOwner});
				sbj.notifyEvent("AnswerBuilt", {'qid': this.questionID});
			}
		}
	},
	
	onReloadAnswers: function()	{
		this.getAjaxAnswer();
	},
	
	getAjaxAnswer: function(){
		var curPlt = this;
		this.onAjax('question', 'get-answers', {qid: this.questionID, page: 0}, 'GET', {
			'onSuccess': function(ret){
				curPlt.answers = ret;
				curPlt.buildAnswer(ret);
			},
			'onFailure': function(msg)	{
				var subject = SingletonFactory.getInstance(Subject);
				var request = new Request("ErrorPage","",{"code":"888", "msg":"Lỗi","content":"Câu hỏi không tồn tại trong hệ thống. Mong bạn thử lại"});
				subject.notifyEvent('RequestRoute', request);
				return;
			}
		});
	},
	
	getAjaxTopicQuestion: function(){
		var curPlt = this;
		this.onAjax("question", "get-all-catchwords-question", {qid: this.questionID}, "GET", {
			onSuccess: function(ret){
				if (ret.length == 0)	{
					var rel = curPlt.getRequest().getParam('rel');
					if (rel == 'ask')	{
						var subject = SingletonFactory.getInstance(Subject);
						subject.notifyEvent('NotifyMessage', 'Bạn vừa đặt câu hỏi nhưng lại không thêm chủ đề cho câu hỏi! Những câu hỏi không có chủ đề <b>mặc định sẽ không được hiển thị tại trang chủ</b>. Để câu hỏi của bạn nhanh chóng có được câu trả lời, bạn hãy thêm chủ đề thích hợp.<br /><img src="resource/images/tutorial-image/addtag.png" alt="addtag" />');
					}
				}
				curPlt.topicsQuestion = ret;
				curPlt.getAjaxAnswer();
				curPlt.buildTopics(ret);
			}
		}, true, 60000);
	},
	
	buildQuestion: function(){
		this.model.qcontent = this.question.title;
		this.model.qdetail = this.question.content.trim().replace(/\\n/g, '<br>');
		this.model.qdate = this.question.since;
		this.model.quser = "";
		this.model.qusertarget = "";
		this.model.avatar = this.ownerAvatar;
		this.model.anonymous = this.question.anonymous;
		this.model.bestSource = this.question.bestSource;
		if(this.question.name != undefined && this.question.name!=""){
			this.quid = this.question.userId;
			var objParam = {};
			objParam.quserid = this.model.quserid = this.question.userId;
			objParam.qusername = this.question.name;
			this.model.quser = this.renderView("UserLink",objParam);
		}
		
		//FIXME: Not yet
		if(this.question.target_name != undefined && this.question.target_name !=""){
			var objParam = {};
			objParam.quserid = this.question.targetId;
			objParam.qusername = this.question.target_name;
			this.model.qusertarget = this.renderView("UserLink",objParam);
		}
	},
	
	buildTopics: function(topicsQuestion){
		var topicAdded = Array();
		var arr = Array();
		for ( var key in topicsQuestion) {
			var objParam = {};
			var curObj = topicsQuestion[key];
			objParam.tid = generateId("tt");
			objParam.content = curObj['catchWord'];
			objParam.cid = curObj['id'];
			objParam.uid = this.quid;
			topicAdded[curObj['id']] = objParam.tid;
			arr.push(this.renderView("Topic",objParam));
		}
		this.requestForEffectiveResource('TopicArea').html(arr.join(','));
		this.requestForEffectiveResource('EditTopicArea').html(this.renderView("EditTopic",{topicsQuestion: topicsQuestion}));
		
		// fetch to cache
		var sysProp = SingletonFactory.getInstance(Application).getSystemProperties();
		sysProp.set("memcached.addedTopics", topicAdded);
		
		//var sbj = SingletonFactory.getInstance(Subject);
		//sbj.notifyEvent("CheckTopicEditable");
	},
	
	buildAnswer : function(answers) {
		var result = $("<div></div>");
		var hidden = $("<div></div>");
		var hiddenNo = 0;
		
		var checkUserAnswered = Array();
		for ( var key in answers) {
			this.answerNum ++;
			var objParam = {};
			var curObj = answers[key];
			objParam.uid = curObj['userId'];
			checkUserAnswered.push(curObj['userId']);
			// TODO: neu uid == this user => no need for mce
			if(curObj['userId'] == this.uid){
				this.needMCE = false;
			}
			objParam.aid = curObj['id'];
			objParam.uimglink = curObj.avatar;
			objParam.uname= curObj.name;
			objParam.avote = curObj['vote'];
			objParam.adate = curObj['since'];
			objParam.acontent = curObj['content'];
			objParam.lastEdited = curObj['lastEdited'];
			objParam.negatives = Array();
			
			//negative comments
			for(var i in curObj['negativeTypes'])	{
				var type = curObj['negativeTypes'][i];
				switch (type)	{
					case 1:
						objParam.negatives.push('Câu trả lời này cần phải đúng trọng tâm câu hỏi hơn');
						break;
					case 2:
						objParam.negatives.push('Câu trả lời này cần đưa ra ý kiến mới so với những câu trả lời trước đó');
						break;
					case 3:
						objParam.negatives.push('Câu trả lời này cần thêm giải thích');
						break;
					case 4:
						objParam.negatives.push('Câu trả lời này nên đưa vào phần bàn luận cho câu trả lời khác');
						break;
					case 5:
						objParam.negatives.push('Chứa nội dung từ nguồn khác nhưng không có chú thích');
						break;
				}
			}
			
			if (curObj.hidden == 1)	{
				var template = this.renderView("HiddenItem", objParam);
				hidden.append(template);
				hiddenNo++;
			}
			else {
				var template = this.renderView("Item", objParam);
				result.append(template);
			}
		}
		
		// Used in plugin
		SingletonFactory.getInstance(Application).getSystemProperties().set("memcached.answeredID",checkUserAnswered);
		this.requestForEffectiveResource('AnswersList').html($(result).html());
		this.requestForEffectiveResource('HiddenAnswersList').html($(hidden).html());
		this.requestForEffectiveResource('HiddenAnswerNo').html(hiddenNo);
		if (hiddenNo == 0)	{
			this.requestForEffectiveResource('HiddenAnswers').hide();
		}
		
		var sbj = SingletonFactory.getInstance(Subject);
		var checkImg = {};
		checkImg.zone = this.requestForEffectiveResource('AnswersList');
		sbj.notifyEvent("RequestProfileImageCheck", checkImg);
		checkImg.zone = this.requestForEffectiveResource('HiddenAnswersList');
		sbj.notifyEvent("RequestProfileImageCheck", checkImg);
		
		this.updateAnswerNum();
		this.initEditor(this.questionID);
		sbj.notifyEvent("BindingChangeAnswer");
		var qid = this.getRequest().getParam('qid');
		sbj.notifyEvent("ShowBio", {'qid': qid});
		sbj.notifyEvent("RenderBioEditLink", {'qid': qid});
		sbj.notifyEvent("AnswerBuilt", {'qid': qid});
		//clean style
		sbj.notifyEvent('CleanFont');
		
		var hl = this.getRequest().getParam('hl');
		if (hl != undefined)	{
			this.requestForEffectiveResource('Outer'+hl).addClass('highlighted');
			$.scrollTo(this.requestForEffectiveResource('Outer'+hl), 800);
		}
	},
	
	updateAnswerNum: function(){
		// update count
		var countPage = parseInt($("#answer-more-btn").attr("page"));
		var sum = this.answerNum + countPage;
		$("#answer-more-btn").attr("page",sum);
	},
	
	initEditor: function(qid)	{
		if(this.needMCE){
			this.requestForEffectiveResource('TextAreaContainer').html(this.renderView('MCE', {'qid': qid}));
			var curID = "AnswerPortlet-AnswerTextEditor";
			var sbj = SingletonFactory.getInstance(Subject);
			sbj.notifyEvent("TinyEditorInit",{id : curID, content: ""});
			sbj.notifyEvent("InitInputMethod",{id : curID, content: ""});
		}
	},
	
	run : function() {
		this.needMCE = true;
		this.getQuestionID();
		this.model.qid = this.questionID;
		this.getAjax();
	},
	
	onSubmitQuestionContent: function()	{
		var qid = this.getRequest().getParam('qid');
		var subject = SingletonFactory.getInstance(Subject);
		var content = this.requestForEffectiveResource('QDetail').find('textarea').val();
		if (content == this.detailOld)	{
			subject.notifyEvent('CancelSubmitQuestionEdit');
			return;
		}
		var obj = this;
		this.onAjax('question', 'edit-question', {content: content, id: qid}, 'POST', {
			'onSuccess': function(ret)	{
				obj.requestForEffectiveResource('QDetail').html(content);
				obj.requestForEffectiveResource('QEditControl').html('');
				obj.editState = 0;
			}
		});
	},
	
	onCancelChangeTopic: function() {
		this.requestForEffectiveResource('EditTopicContainer').hide();
		this.requestForEffectiveResource('TopicArea').parent().show();
		this.editTopicState = 0;
	},
	
	onCancelSubmitQuestionEdit: function()	{
		this.requestForEffectiveResource('QDetail').html(this.detailOld);
		this.requestForEffectiveResource('QEditControl').html('');
		this.editState = 0;
	},
	
	onBookmarkQuestion: function() {
		var subject = SingletonFactory.getInstance(Subject);
		subject.notifyEvent('NeedLogin', {type: 'BookmarkQuestion'});
	},
	
	onLoginSuccess: function(eventData) {
		if (eventData.type == 'BookmarkQuestion')	{
			var obj = this;
			if (!this.requestForEffectiveResource('Bookmark').hasClass('active'))	{
				this.onAjax('question', 'bookmark', {id: this.questionID}, 'post', {
					onSuccess: function(ret) {
						obj.requestForEffectiveResource("Bookmark").addClass('active');
					}
				});
			} else {
				this.onAjax('question', 'remove-bookmark', {id: this.questionID}, 'post', {
					onSuccess: function(ret) {
						obj.requestForEffectiveResource("Bookmark").removeClass('active');
					}
				});
			}
		}
	},
	
	onNewTagSelect: function(eventData) {
		var ui = eventData.ui;
		var txt = ui.item.label;
		var value = ui.item.id;
		var obj = this;
		
		this.onAjax('question', 'add-tag', {id: this.questionID, tagId: value}, 'post', {
			onSuccess: function(ret) {
				obj.requestForEffectiveResource("EditTopicArea").append(obj.renderView('TopicTmpl', {id: value, catchWord: txt}));
			}
		});
	},
	
	onChangeQDetailButtonClick: function() {
		if (this.editState == 1)
			return;
		this.editState = 1;
		var oldContent = this.requestForEffectiveResource('QDetail').html();
		this.requestForEffectiveResource('QDetail').html(this.renderView('QDetailEdit', {oldContent: oldContent}));
		this.detailOld = oldContent;
		this.requestForEffectiveResource('QEditControl').html(this.renderView('QEditControlTmpl', {}));
		var subject = SingletonFactory.getInstance(Subject);
		subject.notifyEvent('ExpandTextArea', {min: 45, max: 200, target: this.requestForEffectiveResource('QDetail').find('textarea')});
	},
	
	onChangeTopicButtonClick: function()	{
		if (this.editTopicState == 1)
			return;
		this.editTopicState = 1;
		this.requestForEffectiveResource('TopicArea').parent().hide();
		this.requestForEffectiveResource('EditTopicContainer').show();
		
		var subject = SingletonFactory.getInstance(Subject);
		var inputBox = this.requestForEffectiveResource("TopicInput");
		var eventData = {};
		eventData.selectCallback = "NewTagSelect";
		eventData.autocompleteObject = inputBox;
		var solrRoot = SingletonFactory.getInstance(Application).getSystemProperties().get('host.solr');
		eventData.autocompleteSource = solrRoot+"/autocomplete/catch";
		eventData.type = "Expertise";
		subject.notifyEvent('NeedAutocomplete', eventData);
		
		subject.notifyEvent('AttachFocusDetection', {target: inputBox, defaultValue: 'Nhập chủ đề cần thêm'});
	},
	
	onQuestionTagDeleteButtonClick: function(event) {
		this.onAjax('question', 'remove-tag', {id: this.questionID, tagId: $(event.target).attr('eid')}, 'post', {
			onSuccess: function() {
				$(event.target).parent().remove();
			}
		});
	},
	
	onReloadPage: function(){
		this.editState = 0;
		this.editTopicState = 0;
		this.run();
	},
	
	onEnd: function()	{
		this.unregisterObserver();
	}
}).implement(RenderInterface).implement(PortletInterface).implement(ObserverInterface).implement(AjaxInterface);

AskBasePortlet = Class.extend({
	init: function()	{
		this.name = "AskBasePortlet";
		this.selectedTopics = new Array();
		this.usingFacebox = false;
	},
	
	_requestForEffectiveResource: function(targetName){
		if(this.usingFacebox){
			return $("#"+this.name+"-"+targetName);
		}else{
			return this.requestForEffectiveResource(targetName);
		}
	},
	
	showPortlet: function(eventData){
		var loggedIn = SingletonFactory.getInstance(Application).getSystemProperties().get('user.login');
		if (loggedIn != 1)	{
			var subject = SingletonFactory.getInstance(Subject);
			subject.notifyEvent("NeedLogin", {type: this.name, event: eventData});
		} else {
			this.doShowPortlet(eventData);
		}
	},
	
	onLoginSuccess: function(eventData)	{
		if (eventData.type != this.name)
			return;
		this.doShowPortlet(eventData.event);
	},
	
	doShowPortlet: function(eventData)	{
		var subject = SingletonFactory.getInstance(Subject);
		this.usingFacebox = true;
		this.selectedPeople = Array();
		this.selectedTopics = Array();

		this.model.askMsg = $("#"+this.name+"-TextAskMessage").html();
		if (eventData.question == undefined)
			eventData.question = "";
		this.model.question = eventData.question;
		subject.notifyEvent('ShowPopup', {id: this.name, title: 'Đặt câu hỏi', content: this.render()});
		this._requestForEffectiveResource('TextBox').focus();
		var target = this._requestForEffectiveResource('TextAreaExtended');
		subject.notifyEvent('ExpandTextArea', {target: target, min: 30, max: 200});
		
		var profile = eventData.profile;
		if (profile != undefined)	{
			for(var i=0;i<profile.length && i<2;i++)	{
				this.appendPeople({value: profile[i].id, txt: profile[i].name});
			}
		}
		
		var subject = SingletonFactory.getInstance(Subject);
		subject.notifyEvent(this.name+'FetchAutocomplete');
	},
	
	fetchAutocomplete: function()	{
		var addTopicInputBox = this._requestForEffectiveResource("AddTopicInputBox"); 
		//FIXME: data should be loaded only once !addTopicInputBox
		var eventData = {};
		eventData.selectCallback = this.name+"TopicSelect";
		eventData.autocompleteObject = addTopicInputBox;
		var solrRoot = SingletonFactory.getInstance(Application).getSystemProperties().get('host.solr');
		eventData.autocompleteSource = solrRoot+"/autocomplete/catch";
		var subject = SingletonFactory.getInstance(Subject);
		subject.notifyEvent('NeedAutocomplete', eventData);
		
		var addPeopleInputBox = this._requestForEffectiveResource("AddPeopleInputBox");
		var eventData = {};
		eventData.selectCallback = this.name+"PeopleSelect";
		eventData.autocompleteObject = addPeopleInputBox;
		eventData.autocompleteSource = solrRoot+"/person/person";
		eventData.type = "person";
		subject.notifyEvent('NeedAutocomplete', eventData);
	},
	
	appendPeople: function(obj)	{
		var txt = obj.txt;
		var value = obj.value;
		
		var topicContainer = this._requestForEffectiveResource("AddPeopleContainer");
		if (this.selectedPeople == undefined)
			this.selectedPeople = Array();
		if (this.selectedPeople.length >= 2)
			return;
		for(var i=0; i<this.selectedPeople.length;i++ ){
			if(this.selectedPeople[i] === value){
				return;
			}
		}
		var textToken = $("<span class='tokenContent'>"+txt+"</span>");
		this.selectedPeople.push(value);
		
		// UI ONLY
		var selectedPeople = this.selectedPeople;
		var span = $("<span>").addClass("edit_tag").append(textToken);
		$("<span>").bind("click",function(event){
			for(var start=0; start<selectedPeople.length; start++ ){
				if(selectedPeople[start] === value){
					break;
				}
			}
			selectedPeople.splice(start, 1);
			$(event.target).parent().remove();
		}).html(" x ").css("text-align","center").appendTo(span);
		topicContainer.append(span);
	},
	
	onBegin: function()	{
		this.model = {};
		this.registerObserver();
	},
	
	run: function()	{
		this.model.optionalMsg = this.getLocalizedText("OptionalMessage");
		this.model.optionalDetailMsg = this.getLocalizedText("OptionalDetailMessage");
		this.model.askMsg = this.getLocalizedText("AskMessage");
		this.model.question = "";
		this.getPortletPlaceholder().drawToCanvas(this.render());
	},
	
	onEnd: function()	{
		this.unregisterObserver();
	},
	
	append: function(eventData)	{
		var txt = eventData.txt;
		var value = eventData.value;
		var topicContainer = this._requestForEffectiveResource("AddTopicContainer");
		if (this.selectedTopics == undefined)
			this.selectedTopics = Array();
		for(var i=0; i<this.selectedTopics.length;i++ ){
			if(this.selectedTopics[i] === value){
				return;
			}
		}
		var textToken = $("<span class='tokenContent'>"+txt+"</span>");
		this.selectedTopics.push(value);
		
		// UI ONLY
		var selectedTopics = this.selectedTopics;
		var span = $("<span>").addClass("edit_tag").append(textToken);
		$("<span>").bind("click",function(event){
			var start = 0;
			for( start=0; start<selectedTopics.length; start++ ){
				if(selectedTopics[start] === value){
					break;
				}
			}
			selectedTopics.splice(start, 1);
			$(event.target).parent().remove();
		}).html(" x ").css("text-align","center").appendTo(span);
		topicContainer.append(span);
	}	
}).implement(PortletInterface).implement(RenderInterface).implement(ObserverInterface).implement(AjaxInterface);
AskHomeQuestionPortlet = Class.extend({
	init: function()	{
		this.name = "AskHomeQuestionPortlet";
	},
	
/*	onBegin: function()	{
		this.model = {};
		this.registerObserver();
	},
	
	onEnd: function()	{
		this.unregisterObserver();
	},*/
	
	run: function() {
		this.getPortletPlaceholder().drawToCanvas(this.render());
		var subject = SingletonFactory.getInstance(Subject);
		subject.notifyEvent('AttachAutocompleteEngine', {type: 'question-only', target: this.requestForEffectiveResource('TextBox')});
	},
	
/*	onAskHomeTextBoxFocus: function(eventData)	{
		this.requestForEffectiveResource("Extended").show();
	},
	
	onAskHomeButtonClick: function(eventData)	{
		var question = this.requestForEffectiveResource("TextBox").val();
		var extended = this.requestForEffectiveResource("TextAreaExtended").val();
		var anonymous = this.requestForEffectiveResource("Anonymous").is(':checked') ? 1 : 0;
		
		if (question == undefined || question.trim() == '')	{
			this.requestForEffectiveResource('QuestionError1').html('Câu hỏi không được để trống');
			return;
		}
		
		var obj = this;
		obj.requestForEffectiveResource("QuestionInfo").html("");
		obj.requestForEffectiveResource("QuestionError").html("");
		obj.requestForEffectiveResource("QuestionError1").html("");
		
		this.onAjax('question', 'add', {'title': question, 'content': extended, anonymous: anonymous}, 'POST', 
			{'onSuccess': function(ret)	{
				var sbj = SingletonFactory.getInstance(Subject);
				sbj.notifyEvent("NotifyGlobal", obj.getLocalizedText("AskSuccess"));
				sbj.notifyEvent("RequestRoute", new Request('Question', null, {qid: ret}));
				
				obj.requestForEffectiveResource("TextBox").val('');
				obj.requestForEffectiveResource("TextAreaExtended").val('');
				obj.requestForEffectiveResource("Extended").hide();
			},
			'onFailure': function(message)	{
				obj.requestForEffectiveResource("QuestionError").html(message);
			}
		});
	}*/
}).implement(PortletInterface).implement(RenderInterface).implement(ObserverInterface).implement(AjaxInterface);
AskQuestionPortlet = AskBasePortlet.extend({
	init: function()	{
		this.name = "AskQuestionPortlet";
		this.selectedTopics = new Array();
		this.usingFacebox = false;
	},
	
	onMakeNewQuestion: function(eventData)	{
		this.showPortlet(eventData);
	},

	onAskQuestionPortletFetchAutocomplete: function()	{
		this.fetchAutocomplete();
	},
	
	onAskQuestionPortletPeopleSelect: function(eventData)	{
		var ui = eventData.ui;
		var txt = ui.item.label;
		var value = ui.item.id;
		this.appendPeople({value: value, txt: txt});
	},
	
	onAskQuestionPortletTopicSelect: function(eventData)	{
		var ui = eventData.ui;
		var txt = ui.item.label;
		var value = ui.item.id;
		
		var subject = SingletonFactory.getInstance(Subject);
		subject.notifyEvent('AskNonTargetQuestionPortletAppend', {'txt': txt, 'value': value});
	},
	
	onAskNonTargetQuestionPortletAppend: function(eventData)	{
		this.append(eventData);
	},
	
	onAskNonTargetTextBoxFocus: function(eventData)	{
		this._requestForEffectiveResource("Extended").show();
	},
	
	onAskNonTargetButtonClick: function(eventData)	{
		var question = this._requestForEffectiveResource("TextBox").val();
		var extended = this._requestForEffectiveResource("TextAreaExtended").val();
		var anonymous = this._requestForEffectiveResource("Anonymous").is(':checked') ? 1 : 0;
		
		if (question == undefined || question.trim() == '')	{
			this._requestForEffectiveResource('QuestionError1').html('Câu hỏi không được để trống');
			return;
		}
		
		var obj = this;
		obj._requestForEffectiveResource("QuestionInfo").html("");
		obj._requestForEffectiveResource("QuestionError").html("");
		obj._requestForEffectiveResource("QuestionError1").html("");
		var selectedTopics = new Array();
		if(this.selectedTopics.length > 0){
			for( var i=0; i<this.selectedTopics.length; i++ ){
				selectedTopics.push(this.selectedTopics[i]); 
			}
		}
		var target_id = undefined;
		var target_next_id = undefined;
		if (this.selectedPeople != undefined && this.selectedPeople.length > 0)	{
			target_id = this.selectedPeople[0];
			if (this.selectedPeople.length > 1)	{
				target_next_id = this.selectedPeople[1];
			}
		}
		
		this.onAjax('question', 'add', {'title': question, 'content': extended, 'catch': selectedTopics.join(','), 'target_id': target_id, 'target_next_id': target_next_id, anonymous: anonymous}, 'POST', 
			{'onSuccess': function(ret)	{
				this.selectedTopics = Array();
				var sbj = SingletonFactory.getInstance(Subject);
				sbj.notifyEvent("NotifyGlobal", obj.getLocalizedText("AskSuccess"));
				sbj.notifyEvent("RequestRoute", new Request('Question', null, {qid: ret, rel: 'ask'}));
				sbj.notifyEvent("PopupRemove", {id: 'AskQuestionPortlet'});
			},
			'onFailure': function(message)	{
				obj._requestForEffectiveResource("QuestionError").html(message);
			}
		});
	}
}).implement(PortletInterface).implement(RenderInterface).implement(ObserverInterface).implement(AjaxInterface);
AskSimilarQuestionPortlet = AskBasePortlet.extend({
	init: function()	{
		this.name = "AskSimilarQuestionPortlet";
		this.selectedTopics = new Array();
		this.usingFacebox = false;
		this.question_id=0;
	},
	
	onMakeNewSimilarQuestion: function(eventData)	{
		var qid=eventData.id;		
		this.question_id=qid;
		this.showPortlet(eventData);
		var obj = this;	
		var txt="";
		var val="";
		this.onAjax('question', 'get-all-catchwords-question', {'qid': qid}, 'GET', {'onSuccess': function(ret)	{
			for (var i=0;i<ret.length;i++)	{
				txt=ret[i].catchWord;
				val=ret[i].id;
				obj.AppendQuestionTopic({'txt':txt, 'value': val});
			}								
		}}, this.useCache, 300000);
	},
	
	onAskSimilarQuestionPortletFetchAutocomplete: function()	{
		this.fetchAutocomplete();
	},
	
	onAskSimilarQuestionPortletPeopleSelect: function(eventData)	{
		var ui = eventData.ui;
		var txt = ui.item.label;
		var value = ui.item.id;
		
		this.appendPeople({value: value, txt: txt});
	},
	
	onAskSimilarQuestionPortletTopicSelect: function(eventData)	{
		var ui = eventData.ui;
		var txt = ui.item.label;
		var value = ui.item.id;
		
		var subject = SingletonFactory.getInstance(Subject);
		subject.notifyEvent('AskSimilarQuestionPortletAppend', {'txt': txt, 'value': value});
	},

	AppendQuestionTopic: function(eventData)	{
		var txt = eventData.txt;
		var value = eventData.value;
		var topicContainer = this._requestForEffectiveResource("AddTopicContainer");
		for(var i=0; i<this.selectedTopics.length;i++ ){
			if(this.selectedTopics[i] === value){
				return;
			}
		}
		var textToken = $("<span class='tokenContent'>"+txt+"</span>");
		this.selectedTopics.push(value);
		
		// UI ONLY
		var selectedTopics = this.selectedTopics;
		var span = $("<span>").addClass("edit_tag").append(textToken);
		$("<span>").bind("click",function(event){
				var start = 0;
				for( start=0; start<selectedTopics.length; start++ ){
					if(selectedTopics[start] === value){
						break;
					}
				}
				selectedTopics.splice(start, 1);
				$(event.target).parent().remove();
			}).html(" x ").css("text-align","center").appendTo(span);
		topicContainer.append(span);
	},
		
	onAskSimilarQuestionPortletAppend: function(eventData)	{
		this.append(eventData);
	},
	
	onAskSimilarTextBoxFocus: function(eventData)	{
		this._requestForEffectiveResource("Extended").show();
	},
	
	onAskSimilarButtonClick: function(eventData)	{
		var question = this._requestForEffectiveResource("TextBox").val();
		var extended = this._requestForEffectiveResource("TextAreaExtended").val();
		
		if (question == undefined || question.trim() == '')	{
			this._requestForEffectiveResource('QuestionError1').html('Câu hỏi không được để trống');
			return;
		}
		
		var obj = this;
		obj._requestForEffectiveResource("QuestionInfo").html("");
		obj._requestForEffectiveResource("QuestionError").html("");
		obj._requestForEffectiveResource("QuestionError1").html("");
		var selectedTopics = new Array();
		if(this.selectedTopics.length > 0){
			for( var i=0; i<this.selectedTopics.length; i++ ){
				selectedTopics.push(this.selectedTopics[i]); 
			}
		}
		var target_id = undefined;
		var target_next_id = 0;
		if (this.selectedPeople != undefined && this.selectedPeople.length > 0)	{
			target_id = this.selectedPeople[0];
			if (this.selectedPeople.length > 1)	{
				target_next_id = this.selectedPeople[1];
			}
		}
		this.onAjax('question', 'add-similar-question', {'similarId':this.question_id,'title': question, 'content': extended, 'catch': selectedTopics.join(','), 'target_id': target_id, 'target_next_id': target_next_id}, 'POST', 
			{'onSuccess': function(ret)	{
				this.selectedTopics = Array();
				var sbj = SingletonFactory.getInstance(Subject);
				sbj.notifyEvent("NotifyGlobal", obj.getLocalizedText("AskSuccess"));
				sbj.notifyEvent("RequestRoute", new Request('Question', null, {qid: ret}));
				sbj.notifyEvent("PopupRemove", {id: 'AskSimilarQuestionPortlet'});
			},
			'onFailure': function(message)	{
				obj._requestForEffectiveResource("QuestionError").html(message);
			}
		});
	}
}).implement(PortletInterface).implement(RenderInterface).implement(ObserverInterface).implement(AjaxInterface);
BookmarkPortlet = Class.extend({
	init: function() {
		this.name = "BookmarkPortlet";
		this.page = 0;
	},
	
	onBegin: function() {
		this.registerObserver();
	},
	
	onReloadPage: function() {
		this.run();
	},
	
	onGetMoreBookmarks: function() {
		this.page++;
		var id = this.getRequest().getParam('id');
		var obj = this;
		this.onAjax('question', 'get-bookmark-questions', {id: id, page: this.page}, 'get', {
			onSuccess: function(ret) {
				obj.model = {list: ret};
				obj.requestForEffectiveResource('Container').append(obj.renderView('QuestionTmpl', obj.model));
				if (ret.length < 10)
					obj.requestForEffectiveResource('ViewMore').hide();
			}
		}, true, 300000);
	},
	
	run: function() {
		var id = this.getRequest().getParam('id');
		var obj = this;
		this.onAjax('question', 'get-bookmark-questions', {id: id}, 'get', {
			onSuccess: function(ret) {
				obj.model = {list: ret};
				obj.getPortletPlaceholder().paintCanvas(obj.render());
				obj.requestForEffectiveResource('Container').html(obj.renderView('QuestionTmpl', obj.model));
				if (ret.length < 10)
					obj.requestForEffectiveResource('ViewMore').hide();
			}
		}, true, 300000);
	},
	
	onEnd: function() {
		this.unregisterObserver();
	}
}).implement(PortletInterface).implement(RenderInterface).implement(AjaxInterface).implement(ObserverInterface);
ExtraQuestionsPortlet = Class.extend({
	init: function() {
		this.name = "ExtraQuestionsPortlet";
	},
	
	onBegin: function() {
		this.registerObserver();
	},
	
	onQuestionNotificationFetched: function(maxId) {
		var obj = this;
		this.onAjax('question', 'get-latest-questions', {qid: maxId}, 'get', {
			onSuccess: function(ret) {
				obj.model = {list: ret};
				if (ret.length > 0)
					obj.getPortletPlaceholder().paintCanvas(obj.render());
			}
		}, true, 300000);
	},
	
	onEnd: function() {
		this.unregisterObserver();
	}
}).implement(PortletInterface).implement(RenderInterface).implement(AjaxInterface).implement(ObserverInterface);
QuestionActionPortlet = Class.extend({
	init: function()	{
		this.name = "QuestionActionPortlet";
	},
	
	onBegin: function()	{
		this.registerObserver();
	},
	
	onChangeBestSourceMark: function() {
		var subject = SingletonFactory.getInstance(Subject);
		var obj = this.requestForEffectiveResource('BestSourceBtn');
		var bs = obj.attr('bestSource');
		if (bs == 1)	{
			subject.notifyEvent('ShowPopup', {id: 'QuestionBestSource', title: 'Đánh dấu câu hỏi chất lượng', content: this.renderView('AddBestSource', {})});
		} else {
			subject.notifyEvent('ShowPopup', {id: 'QuestionBestSource', title: 'Bỏ đánh dấu câu hỏi chất lượng', content: this.renderView('RemoveBestSource', {})});
		}
	},
	
	onMarkBestSource: function() {
		var bestSource = $('#'+this.name+'-BestSourceReason').val();
		if (bestSource == "")	{
			$('#'+this.name+'-BestSourceError').val('Bạn phải nhập lý do');
			return;
		}
		var subject = SingletonFactory.getInstance(Subject);
		this.onAjax('question', 'mark-best-source', {id: this.questionID, reason: bestSource}, 'POST', {
			onSuccess: function(ret) {
				subject.notifyEvent('PopupRemove', {id: 'QuestionBestSource'});
				subject.notifyEvent('ReloadPage');
			}
		});
	},
	
	onRemoveBestSource: function() {
		var subject = SingletonFactory.getInstance(Subject);
		this.onAjax('question', 'remove-best-source', {id: this.questionID}, 'POST', {
			onSuccess: function(ret) {
				subject.notifyEvent('PopupRemove', {id: 'QuestionBestSource'});
				subject.notifyEvent('ReloadPage');
			}
		});
	},
	
	onChangeQuestionAnonymous: function() {
		var obj = this.requestForEffectiveResource('AnonymousBtn');
		this.onAjax('question', 'change-anonymous', {id: this.questionID, anonymous: obj.attr('anonymous')}, 'POST', {
			onSuccess: function(ret) {
				var subject = SingletonFactory.getInstance(Subject);
				subject.notifyEvent('ReloadPage');
			}
		});
	},
	
	onUnfollowQuestion: function(eventData)	{
		var id = eventData.id;
		var obj = this;
		this.onAjax('question', 'unfollow-question', {'id': id}, 'POST', {
			'onSuccess': function(ret)	{
				obj.requestForEffectiveResource('FollowBtn').html(tmpl('QuestionFollowTmpl-Follow', {id: id}));
				var subject = SingletonFactory.getInstance(Subject);
				subject.notifyEvent('QuestionFollowerChange');
			}
		});
	},
	
	onFollowQuestion: function(eventData)	{
		var id = eventData.id;
		var obj = this;
		this.onAjax('question', 'follow-question', {'id': id}, 'POST', {
			'onSuccess': function(ret)	{
				obj.requestForEffectiveResource('FollowBtn').html(tmpl('QuestionFollowTmpl-Unfollow', {id: id}));
				var subject = SingletonFactory.getInstance(Subject);
				subject.notifyEvent('QuestionFollowerChange');
			}
		});
	},
	
	onEnd: function()	{
		this.unregisterObserver();
	},
	
	onAjaxQueryFetched: function(eventData) {
		var root = SingletonFactory.getInstance(Application).getSystemProperties().get('host.root');
		if (eventData.url == root+'/question/get-question-detail')	{
			this.model = eventData.result.data;
			this.questionID = this.model.qid = this.getRequest().getParam('qid');
			this.getPortletPlaceholder().paintCanvas(this.render());
			
			var props = SingletonFactory.getInstance(Application).getSystemProperties();
			var loggedin = props.get('user.login');
			if (loggedin == 0)
				return;
			
			var obj = this;
			this.onAjax('question', 'is-user-following', {'id': obj.questionID}, 'GET', {
				'onSuccess': function(ret)	{
					var follow = '';
					if (ret == true)	{
						follow = 'Unfollow';
					} else {
						follow = 'Follow';
					}
					obj.requestForEffectiveResource('FollowBtn').html(tmpl('QuestionFollowTmpl-'+follow, {id: obj.questionID}));
				}
			});
		}
	}
}).implement(PortletInterface).implement(RenderInterface).implement(AjaxInterface).implement(ObserverInterface);
QuestionSharePortlet = Class.extend({
	init: function()	{
		this.name = "QuestionSharePortlet";
		this.usingFacebox = false;
		
		this.answers = null;
		this.question = null;
		
		this.questionID = null;
		this.linkQuestion = null;
		this.strQuestionTitle = null;
		this.linkAction = null;
		this.avatarAsker = null;
		this.strCaption = 'asking.vn';
		this.strDefaultMessage = '';
		this.strActionName = null;
		this.strDesciption = null;

		this.root = SingletonFactory.getInstance(Application).getSystemProperties().get("host.root");
		
    	window.fbAsyncInit = function() {
		    FB.init({appId: '192257437556427', status: true, cookie: true, xfbml: false});
    	};
	},
	
	requestForEffectiveResource: function(targetName){
		if(this.usingFacebox){
			return $("#"+this.name+"-"+targetName);
		}else{
			return this._super.requestForEffectiveResource(targetName);
		}
	},
	
	onBegin: function()	{
		this.model = {};
		this.registerObserver();
	},
	
	onEnd: function()	{
		this.unregisterObserver();
	},
	
	onAjaxQueryFetched: function(eventData) {
		var root = SingletonFactory.getInstance(Application).getSystemProperties().get('host.root');
		if (eventData.url == root+'/question/get-question-detail')	{
			this.question = eventData.result.data;
		} else if (eventData.url == root+'/question/get-answers')	{
			this.answers = eventData.result.data;
		}
	},
	
	onShareFacebook: function(eventData)	{
		this.questionID = this.getRequest().getParam('qid');
		
		var loggedIn = SingletonFactory.getInstance(Application).getSystemProperties().get('user.login');
		if (loggedIn != 1)	{
			var subject = SingletonFactory.getInstance(Subject);
			subject.notifyEvent("NeedLogin", {type: 'ShareFacebook', event: eventData});
		} else {
			this.publishSharing();
		}	
	},
	
	onLoginSuccess: function(eventData)	{
		if (eventData.type != 'ShareFacebook')
			return;
		this.publishSharing();
	},
	
	publishSharing: function() {
		this.buildContent();
		this.startShare();
	},
	
	buildContent: function(){		
		var count=0;
		if(this.question.avatar == undefined || this.question.avatar == ""){ //assign default avatar of bkprofile
			this.avatarAsker = "http://asking.vn/resource/images/home/bee24.png";
		}else{
			this.avatarAsker = "http://asking.vn/resource/avatar/" + this.question.avatar;	
		}
		this.strQuestionTitle = this.question.title;
		this.linkAction = "http://asking.vn/#!page/Question/qid/" + this.questionID;
		
		for ( var key in this.answers){count++;} //get length of answers.
		var max = -1;
		for ( var key in this.answers){
			var curObj = this.answers[key];
			if (curObj['vote'] > max)	{
				this.strDescription = "Trả lời tốt nhất: " + $('<div>'+curObj['content']+'</div>').text();
				max = curObj.vote;
			}
		}
		if (count == 0){
			this.strActionName = 'Trả lời câu hỏi';
			this.strDescription = this.question.content.trim().replace(/\\n/g, '<br />');
		} else {
			this.strActionName = count+' trả lời';
		}
		return;
	},
	
	startShare: function() {
		var curPlt = this;
		 FB.ui(
		   {
		     method: 'feed',
		     name: this.strQuestionTitle,
		     link: 'http://asking.vn#!page/Question/qid/'+this.questionID,
		     picture: this.avatarAsker,
		     caption: this.strCaption,
		     description: this.strDescription,
		     message: this.strDefaultMessage,
		     actions: [
    			{ name: this.strActionName, link: this.linkAction }
  			 ],
		   },
		   function(response) {
		     if (response && response.post_id) {
		       var sbj = SingletonFactory.getInstance(Subject);
		       /*curPlt.onAjax('question', 'add-share-facebook', {'question_id': curPlt.questionID, 'session_id': response.post_id}, 'POST', 
				{'onSuccess': function(ret)	{
					var sbj = SingletonFactory.getInstance(Subject);
					sbj.notifyEvent("NotifyGlobal", curPlt.getLocalizedText("SetDataSuccess"));
				},
				'onFailure': function(message)	{
					var sbj = SingletonFactory.getInstance(Subject);
					sbj.notifyEvent("NotifyGlobal", curPlt.getLocalizedText("SetDataFailure"));
				}
				});*/    
			   sbj.notifyEvent("NotifyGlobal", "Bạn đã chia sẻ câu hỏi trên Facebook thành công");
		     }
		   }
 		);
	},

	run: function()	{
		this.getPortletPlaceholder().paintCanvas(this.render());
		var e = document.createElement('script'); e.async = true;
	    e.src = document.location.protocol + '//connect.facebook.net/en_US/all.js';
	    $("#fb-root").append(e);
	},
}).implement(PortletInterface).implement(RenderInterface).implement(AjaxInterface).implement(ObserverInterface);
RecommendAnswerPortlet = Class.extend({
	init: function()	{
		this.name = "RecommendAnswerPortlet";
		this.usingFacebox = false;
	},
	
	onBegin: function()	{
		this.model = {};
		this.registerObserver();
	},
	
	onEnd: function()	{
		this.unregisterObserver();
	},
	
	onReloadPage: function()	{
		this.run();
	},
	
	run: function()	{
		this.question_id = this.getRequest().getParam('qid');
		this.getPortletPlaceholder().paintCanvas(this.render());
		
		var obj = this;
		var subject = SingletonFactory.getInstance(Subject);
		this.selectedPeople = undefined;
		
		this.onAjax('question', 'get-forwarded-answerers', {qid: this.question_id}, 'GET', {
			onSuccess: function(ret)	{
				obj.requestForEffectiveResource('AddedContainer').html(obj.renderView('AddedTmpl', {list: ret}));
				subject.notifyEvent('RequestProfileImageCheck', {zone: obj.requestForEffectiveResource('AddedContainer')});
			}
		});
		
		subject.notifyEvent('AttachFocusDetection', {target: this.requestForEffectiveResource('AddPeopleInputBox'), defaultValue: 'Nhập tên của người muốn mời'});
		
		var addPeopleInputBox = this.requestForEffectiveResource("AddPeopleInputBox");
		var eventData = {};
		eventData.selectCallback = "TargetPeopleSelect";
		eventData.autocompleteObject = addPeopleInputBox;
		var solrRoot = SingletonFactory.getInstance(Application).getSystemProperties().get('host.solr');
		eventData.autocompleteSource = solrRoot+"/person/person?rows=5";
		eventData.type = "RecommendPerson";
		subject.notifyEvent('NeedAutocomplete', eventData);
	},
	
	onRecommendEmail: function() {
		var subject = SingletonFactory.getInstance(Subject);
		subject.notifyEvent('ShowPopup', {id: 'RecommendAnswer', title: 'Mời trả lời qua email', content: this.renderView('EmailRecommend', {})});
	},
	
	onTargetPeopleSelect: function(eventData)	{
		var ui = eventData.ui;
		var txt = ui.item.label;
		var value = ui.item.id;
		if (ui.item.type == 'email') {
			var subject = SingletonFactory.getInstance(Subject);
			subject.notifyEvent('RecommendEmail');
			return;
		}
		this.appendPeople({value: value, txt: txt});
	},
	
	appendPeople: function(obj)	{
		var txt = obj.txt;
		var value = obj.value;
		
		var topicContainer = this.requestForEffectiveResource("AddPeopleContainer");
		if (this.selectedPeople == undefined)
			this.selectedPeople = Array();
		if (this.selectedPeople.length >= 2)
			return;
		for(var i=0; i<this.selectedPeople.length;i++ ){
			if(this.selectedPeople[i] === value){
				return;
			}
		}
		var textToken = $("<span class='tokenContent'>"+txt+"</span>");
		this.selectedPeople.push(value);
		if (this.selectedPeople.length == 1)	{
			this.requestForEffectiveResource('SubmitButtonContainer').show();
		}
		
		// UI ONLY
		var obj = this;
		var selectedPeople = this.selectedPeople;
		var span = $("<span>").addClass("edit_tag").append(textToken);
		$("<span>").bind("click",function(event){
			for(var start=0; start<selectedPeople.length; start++ ){
				if(selectedPeople[start] === value){
					break;
				}
			}
			selectedPeople.splice(start, 1);
			$(event.target).parent().remove();
			if (selectedPeople.length == 0)	{
				obj.requestForEffectiveResource('SubmitButtonContainer').hide();
			}
		}).html(" x ").css("text-align","center").appendTo(span);
		topicContainer.append(span);
	},
		
	checkEmail: function(strEmail) {
		var atpos = strEmail.indexOf("@");
		var dotpos = strEmail.lastIndexOf(".");
		if (atpos<1 || dotpos<atpos+2 || dotpos+2>=strEmail.length){
		  	return false;
	 	}
	 	return true;
	},

	onRecommendAnswerButtonClick: function(eventData)	{
		var subject = SingletonFactory.getInstance(Subject);
		subject.notifyEvent('NeedLogin', {type: 'RecommendAnswerButtonClick', evtData: eventData});
	},
	
	onEmailRecommendButtonClick: function(eventData) {
		var subject = SingletonFactory.getInstance(Subject);
		subject.notifyEvent('NeedLogin', {type: 'EmailRecommendButtonClick', evtData: eventData});
	},
	
	onLoginSuccess: function(eventData)	{
		var obj = this;
		if (eventData.type == 'EmailRecommendButtonClick')	{
			$('#RecommendAnswerPortlet-Error').html("");
	 	   	if( this.checkEmail($("#RecommendAnswerPortlet-AddEmailInputBox").val()) ){
	 	   		var emailtarget = $("#RecommendAnswerPortlet-AddEmailInputBox").val();
	 	   		var msg = $("#RecommendAnswerPortlet-OptionalMsg").val();
	 	   		this.onAjax('question', 'add-recommend-email', {msg: msg, question_id: this.question_id, email: emailtarget}, 'POST', {
					'onSuccess': function(ret)	{
						var sbj = SingletonFactory.getInstance(Subject);
						sbj.notifyEvent("NotifyGlobal", "Bạn đã mời trả lời thành công");
						sbj.notifyEvent("PopupRemove", {id: 'RecommendAnswer'});
					},
					'onFailure': function(message)	{
						$('#RecommendAnswerPortlet-Error').html(message);
					}
				});//end onAjax
	 	   }else{
	 		  $('#RecommendAnswerPortlet-Error').html("Email không hợp lệ");
	 	   }//end if check email address
		} else if (eventData.type == 'RecommendAnswerButtonClick') {
			var selectedPeople = new Array();
			if (this.selectedPeople != undefined && this.selectedPeople.length > 0)	{
				for (var i=0; i<this.selectedPeople.length; i++){
					selectedPeople.push(this.selectedPeople[i]);
				}
			}//end 
			this.onAjax('question', 'forward-question', {'qid': this.question_id, 'target_id': selectedPeople.join(',')}, 'POST', 
				{'onSuccess': function(ret)	{
					obj.onReloadPage();
				},
				'onFailure': function(message)	{
					obj.requestForEffectiveResource("QuestionError").html(obj.getLocalizedText("AskError"));
				}
			});//end onAjax
		}//end if recommend user
	}
}).implement(PortletInterface).implement(RenderInterface).implement(AjaxInterface).implement(ObserverInterface);
SimilarQuestionsPortlet = Class.extend({
	init: function()	{
		this.name = "SimilarQuestionsPortlet";
		this.questionID = null;
	},
	
	onBegin: function()	{
		this.registerObserver();
	},
	
	onEnd: function()	{
		this.unregisterObserver();
	},
	
	run: function()	{
		this.questionID = this.getRequest().getParam('qid');
		this.getPortletPlaceholder().paintCanvas(this.render());
		this.fetch();
		var subject = SingletonFactory.getInstance(Subject);
		subject.notifyEvent('AttachFocusDetection', {target: this.requestForEffectiveResource('AddQuestionInputBox'), defaultValue: 'Nhập câu hỏi tương tự'});
		
		var AddQuestionInputBox = this.requestForEffectiveResource("AddQuestionInputBox");
		var eventData = {};
		eventData.selectCallback = "SimilarQuestionSelect";
		eventData.autocompleteObject = AddQuestionInputBox;
		var solrRoot = SingletonFactory.getInstance(Application).getSystemProperties().get('host.solr');
		eventData.autocompleteSource = solrRoot+"/autocomplete/question";
		eventData.type = "Question";
		subject.notifyEvent('NeedAutocomplete', eventData);
	},
	
	onRemoveSimilarQuestion: function(event)	{
		$(event.target).parent().remove();
	},
	
	onSimilarQuestionsButtonClick: function()	{
		var ids = Array();
		this.requestForEffectiveResource('AttachQuestions').find('[qid]').each(function() {
			ids.push($(this).attr('qid'));
		});
		
		if (ids.length != 0)	{
			var obj = this;
			this.onAjax('question', 'attach-similar-questions', {ids: ids.join(','), id: this.questionID}, 'post', {
				onSuccess: function()	{
					obj.run();
				}
			});
		} else {
			this.requestForEffectiveResource('SimilarQuestions').show();
			this.requestForEffectiveResource('AttachQuestions').hide();
		}
	},
	
	onSimilarQuestionSelect: function(eventData) {
		var ui = eventData.ui;
		var txt = ui.item.label;
		var value = ui.item.id;
		var topicContainer = this.requestForEffectiveResource("AddQuestionContainer");
		
		$(topicContainer).append(this.renderView('QuestionTmpl', {id: value, label: txt}));
	},
	
	fetch: function()	{
		var obj = this;
		this.onAjax('question', 'get-similar-questions', {qid: obj.questionID}, 'GET', {
			'onSuccess': function(ret)	{
				obj.requestForEffectiveResource('SimilarQuestions').html(obj.renderView('SimilarQuestionsTmpl', {user: ret}));
			}
		});
	},
	
	onViewAllSimilarQuestions: function()	{
		var obj = this;
		this.onAjax('question', 'get-similar-questions', {qid: obj.questionID, all: 1}, 'GET', {
			'onSuccess': function(ret)	{
				obj.requestForEffectiveResource('SimilarQuestions').html(obj.renderView('SimilarQuestionsTmpl', {user: ret}));
				obj.requestForEffectiveResource('ViewMore').remove();
			}
		});
	},
	
	onAttachSimilarQuestions: function()	{
		this.requestForEffectiveResource('SimilarQuestions').hide();
		this.requestForEffectiveResource('AttachQuestions').show();
	},
	
	onReloadPage: function(){
		this.run();
	}
}).implement(PortletInterface).implement(AjaxInterface).implement(RenderInterface).implement(ObserverInterface);
SameQuestionsPortlet = Class.extend({
	init: function()	{
		this.name = "SameQuestionsPortlet";
		this.questionID = null;
		this.start = 0;
	},
	
	onBegin: function()	{
		this.registerObserver();
	},
	
	onEnd: function()	{
		this.unregisterObserver();
	},
	
	run: function()	{
		this.getPortletPlaceholder().paintCanvas(this.render());
	},
	
	onAjaxQueryFetched: function(eventData) {
		var root = SingletonFactory.getInstance(Application).getSystemProperties().get('host.root');
		if (eventData.url == root+'/question/get-all-catchwords-question')	{
			var catches = Array();
			for(var i in eventData.result.data)	{
				catches.push(eventData.result.data[i].catchWordId);
			}
			this.catches = catches;
			this.fetch();
		}
	},
	
	fetch: function()	{
		var obj = this;
		var questionId = this.getRequest().getParam('qid');
		$.getJSON('/solr/knowledge/intopic?wt=json&rows=5', {q: this.catches.join(' ')}, function(ret) {
			obj.requestForEffectiveResource('QuestionsContainer').html(obj.renderView('QuestionsTmpl', {question: ret.response.docs, currentId: questionId}));
			if (ret.response.docs.length < 5)	{
				obj.requestForEffectiveResource('ViewMore').hide();
			}
		});
	},
	
	onViewMoreSameQuestions: function()	{
		var obj = this;
		this.start += 5;
		var questionId = this.getRequest().getParam('qid');
		$.getJSON('/solr/knowledge/intopic?wt=json&rows=5&start='+this.start, {q: this.catches.join(' ')}, function(ret) {
			if (ret.response.docs.length < 5)	{
				obj.requestForEffectiveResource('ViewMore').hide();
			}
			obj.requestForEffectiveResource('QuestionsContainer').append(obj.renderView('QuestionsTmpl', {question: ret.response.docs, currentId: questionId}));
		});
	},
	
	onReloadPage: function(){
		this.run();
	}
}).implement(PortletInterface).implement(AjaxInterface).implement(RenderInterface).implement(ObserverInterface);
ShuffleQuestionsPortlet = Class.extend({
	init: function()	{
		this.name = "ShuffleQuestionsPortlet";
	},
	
	onBegin: function()	{
		this.registerObserver();
	},
	
	onEnd: function()	{
		this.unregisterObserver();
	},
	
	run: function()	{
		this.getPortletPlaceholder().paintCanvas(this.render());
		this.fetch();
	},
	
	onFetchShuffleQuestions: function() {
		this.fetch();
	},
	
	fetch: function()	{
		var obj = this;
		this.onAjax('question', 'get-shuffle-questions', {}, 'GET', {
			'onSuccess': function(ret)	{
				obj.requestForEffectiveResource('Questions').html(obj.renderView('QuestionsTmpl', {user: ret}));
			}
		});
	},
	
	onReloadPage: function(){
		this.fetch();
	}
}).implement(PortletInterface).implement(AjaxInterface).implement(RenderInterface).implement(ObserverInterface);
SearcherPortlet = Class.extend({
	init:function() {
		this.name = "SearcherPortlet";
	},
	
	onBegin: function()	{
		this.registerObserver();
	},
	
	onSearchInputKeyup: function(event)	{
		var keyup = event.keyCode;
		var subject = SingletonFactory.getInstance(Subject);
		if (this.getRequest().getParam('page') == 'Search')	{
			subject.notifyEvent('SearchButtonClick');
		}
		if (keyup == 13)	{
			subject.notifyEvent('SearchButtonClick');
		}
	},
	
	onSearchButtonClick: function(eventData)	{
		$('ul.ui-autocomplete').hide();
		
		var input = this.requestForEffectiveResource('Input');
		if (input.val().trim() == '')	{
			return;
		}
		var txt = input.val().trim();
		
		//knowledge or profile?
		var selected = $('input[name=rd_search]:checked');
		var id = selected.val();
		var request = undefined;
		if (id == 1)	{
			request = new Request('Search', undefined, {type: 'person-search', query: txt});
		} else {
			request = new Request('Search', undefined, {type: 'question-search', query: txt});
		}
		var subject = SingletonFactory.getInstance(Subject);
		subject.notifyEvent('RequestRoute', request);
	},
	
	onSearcherTypeChange: function(eventData)	{
		var selected = $('input[name=rd_search]:checked');
		var id = selected.val();
		var subject = SingletonFactory.getInstance(Subject);
		$('.customStyleSelectBoxInner').html(selected.html());
		
		if (id == 1)	{
			subject.notifyEvent('ChangeAutocompleteType', {type: 'person', target: this.requestForEffectiveResource('Input')});
		} else {
			subject.notifyEvent('ChangeAutocompleteType', {type: 'question', target: this.requestForEffectiveResource('Input')});
		}
	},
	
	onDisplayHeaderHelp:function(eventData){
		jQuery("#headerhelp").slideToggle();
        var closetimer = undefined;
        $("#headerhelp").mouseleave(function() {
            closetimer = setTimeout("jQuery(\"#homehelp\").fadeOut(); jQuery(\"#maphelp\").fadeOut();jQuery(\"#nearplace-help\").fadeOut();",8000);
        });
        $("#headerhelp").mouseover(function() {
            window.clearTimeout(closetimer);
            closetimer = undefined;
        });
	},
	
	onSystemPropertyChanged: function(eventData) {
		if (eventData == 'user.login')
			this.run();
	},
	
	run: function() {
		var logged = SingletonFactory.getInstance(Application).getSystemProperties().get('user.login');
		if (logged == 1) {
			this.getPortletPlaceholder().paintCanvas(this.render());
		} else {
			this.getPortletPlaceholder().paintCanvas('');
		}
	},
	
	onEnd: function()	{
		this.unregisterObserver();
	}
}).implement(RenderInterface).implement(PortletInterface).implement(ObserverInterface);
SearchResultPortlet = Class.extend({
	init : function() {
		this.name = "SearchResultPortlet";
		this.model = {};
		this.pageType = "";//Profile; Knowledge; 
		this.query = "";
		this.configData = null;
		this.pltParams = null;
		this.dataResJSON = null;
		this.highlightResJSON = null;
		this.numDocs = null;
		this.start = null;
		this.rows = null;
		this.root = SingletonFactory.getInstance(Application).getSystemProperties().get("host.root");
		this.searchCore = "";
		this.searchHandler = "";
		this.core = "";
		this.isShuffleResult = false;
	},
	
	onBegin: function()	{
		this.registerObserver();
		this.prepareInitialConfig();
		this.prepareData();
	},
	
	prepareInitialConfig: function()	{
		this.pltParams = this.getInitParameters();
		var params = this.getRequest().getParams();
		this.core = this.pltParams['type'] || params['type'] || "notification-filter";
		this.page = this.pltParams['page'] || params['page'];
		this.isShuffleResult = this.pltParams['shuffle'] || false;
		this.rows = this.pltParams['rows'] || params['rows'] || 10;
		this.shuffleNo = this.pltParams['shuffleNo'] || this.rows;
	},
	
	// done
	prepareData: function(){
		var request = this.getRequest();
		var params = request.getParams();
		this.query = params['query'] || "*:*";
		this.expertises = params['expertises'];
		this.profileExcluded = params['profileExcluded'];
		this.first = true;
		
		this.query = this.getRequest().getParam('id', SingletonFactory.getInstance(Application).getSystemProperties().get("user.id"));
		
		// fixed
		switch(this.core){
			case "user-feed":
				this.pageType = "Feed";
				break;
			case "person-search" :
			case "person-best" :
			case "person-hardcore" :
			case "person-similar" :
			case "person-recommendation":
				this.pageType = "Person";
				break;
			case "question-latest" :
			case "question-best" :
			case "question-open" :
				this.pageType = "Notification";
				break;
			case "notification-filter" :
				this.pageType = "Notification";
				break;
			case "question-flagged":
			case "catchword-filter" :
			case "question-asked" :
			case "question-asking" :
			case "answer" :
				this.pageType = "Notification";
				this.query = this.getRequest().getParam('id', this.query);
				break;
			case "question-search" :
			default:
				this.pageType = "Knowledge";
				break;
		}
		
		this.searchPage = params['search-page'] || this.pltParams['start'] || 0;
		this.configData = this.getConfigData();
	},
	
	processQuery: function(query){
		if (query == undefined) return query;
		if(this.core == "catchword-filter"){
			query = '"' + query + '"';
		}
		
		return query;
	},
	
	// good
	getDataFromServer: function(){
		var currentPorlet = {};
		var obj = this;
		var params = {'start': this.searchPage*this.rows, 'rows': this.rows, 'type': this.core.toLowerCase()};
		var scope = this.scope;
		var login = SingletonFactory.getInstance(Application).getSystemProperties().get('user.login');
		if (scope == 'all' || login != 1)	{
			params.all = 1;
		}
		var all = params.all;
		switch(this.core) {
		case "user-feed":
			params.core = "feed";
			params.handler = "user";
			var props = SingletonFactory.getInstance(Application).getSystemProperties();
			var id = undefined;
			if (props.get('user.login') == 1) {
				id = props.get('user.id');
			}
			params.query = this.getRequest().getParam('id') || id;
			break;
		case "question-asked":
			params.core = "knowledge";
			params.handler = "questionasked";
			params.query = this.query;
			break;
		case "question-asking":
			params.core = "knowledge";
			params.handler = "questionasking";
			params.query = this.query;
			break;
		case "answer":
			params.core = "knowledge";
			params.handler = "answer";
			params.query = this.query;
			break;
		case "question-flagged":
			params.core = "knowledge";
			params.handler = "flagged";
			params.query = this.query;
			break;
		case "person-search" :
			params.core = "person";
			params.handler = "person";
			params.query = this.getRequest().getParam('query');
			break;
		case "person-best" :
			params.core = "person";
			params.handler = "best";
			if(all == 1){
				params.query = "";
			} else {
				params.query = this.query;
			}
			break;
		case "question-search" :
			params.core = "knowledge";
			params.handler = "knol";
			params.query = this.getRequest().getParam('query');
			break;
		case "question-latest" :
			params.core = "knowledge";
			params.handler = "latest";
			break;
		case "question-best" :
			params.core = "knowledge";
			params.handler = "best";
			break;
		case "question-open" :
			params.core = "knowledge";
			params.handler = "open";
			if(all == 1){
				params.query = "";
			} else {
				params.query = this.query;
			}
			break;
		case "catchword-filter" :
			params.core = "knowledge";
			params.handler = "catchword";
			params.query = this.query;
			break;
		case "notification-filter" :
			params.core = "knowledge";
			params.handler = "notification";
//			if(all == 1){
				params.query = "";
//			} else {
//				params.query = this.query;
//			}
			break;
		default :
			params.core = "knowledge";
			params.handler = "notification";
			if(all == 1){
				params.query = "";
			} else {
				params.query = this.query;
			}
			break;
		}
		
		this.query = params.query;
		
		// for hardcore person search
		if(this.expertises != null && this.expertises != ""){
			params.expertises = this.expertises;
		}
		// for hardcore similar search
		if(this.profileExcluded != null && this.profileExcluded != ""){
			params.profileExcluded = this.profileExcluded;
		}
		params.query = this.processQuery(params.query);
		
		var sbj = SingletonFactory.getInstance(Subject);
		sbj.notifyEvent("BeginSearching");
		
		var solrRoot = SingletonFactory.getInstance(Application).getSystemProperties().get('host.solr');
		var url = solrRoot+"/" + params.core + "/" + params.handler + "?wt=json&version=2.2&echoParams=NONE";
		
		params.q = params.query;
		params.query = params.core = params.handler = undefined;
		
		sbj.notifyEvent('AjaxBegan');
		$.getJSON(url, params, function(ret){
			sbj.notifyEvent('AjaxFinished');
			try {
				currentPorlet.start = ret.response.start;
				currentPorlet.numDocs = ret.response.numFound;
				currentPorlet.dataResJSON = ret.response.docs;
				currentPorlet.highlightResJSON = ret.highlighting;
			} catch (err)	{
				currentPorlet.start = 0;
				currentPorlet.numDocs = 0;
				currentPorlet.dataResJSON = {};
				currentPorlet.highlightResJSON = {};
			}
			
			obj.start = currentPorlet.start;
			obj.qtime = ret.responseHeader.QTime/1000;
			obj.numDocs = currentPorlet.numDocs;
			obj.dataResJSON = currentPorlet.dataResJSON;
			obj.highlightResJSON = currentPorlet.highlightResJSON;
			
			if (obj.numDocs == 0 || obj.dataResJSON.length - obj.start >= obj.numDocs)	{
				sbj.notifyEvent("NoMoreResult");
			}
			if (obj.core == "notification-filter" && obj.numDocs <= 50 && all != 1)	{
				obj.onAjax('user-ajax', 'get-following-topic-id', {}, 'GET', {
					onSuccess: function(ret) {
						if (ret != "")	{
							ret = ret.split(',');
							obj.currentTopics = ret;
							ret = ret.join(' ');
							var url = solrRoot+"/knowledge/catchword?wt=json&version=2.2&echoParams=NONE";
							$.getJSON(url, {q: ret, rows: params.rows}, function(ret) {
								if (ret.response.docs.length == obj.prevNumDocs)	{
									return;
								}
								obj.prevNumDocs = obj.numDocs = ret.response.numFound;
								obj.dataResJSON = ret.response.docs;
								if (obj.numDocs > 50)	{
									obj.display();
								} else	{
									obj.suggestFollow();
									if (obj.numDocs > 0) {
										obj.display('SuggestTopList');
										obj.requestForEffectiveResource('SuggestTopList').slideDown(1500);
									}
								}
							});
						} else {
							obj.suggestFollow();
						}
					}
				});
				return;
			}
			
			obj.display();
		});
	},
	
	onFollowTopicViaSuggest: function(id) {
		var obj = this;
		this.onAjax('user-ajax', 'add-single-interest', {id: id}, 'post', {
			onSuccess: function(ret) {
				obj.run();
			}
		});
	},
	
	suggestFollow: function() {
		var obj = this;
		obj.getPortletPlaceholder().paintCanvas(obj.renderView('SuggestFollow', {}));
		//TODO: static => dynamic
		var topics = Array();
		var solrRoot = SingletonFactory.getInstance(Application).getSystemProperties().get('host.solr');
		var url = solrRoot+"/knowledge/bestcatch?wt=json&version=2.2&echoParams=NONE&rows=3";
		
		var checked = Array();
		for(var i in obj.currentTopics)	{
			checked[obj.currentTopics[i]] = obj.currentTopics[i];
		}
		
		if (checked[41] == undefined)
			topics.push({id: 41, title: 'Công nghệ thông tin'});
		if (checked[50] == undefined)
			topics.push({id: 50, title: 'Tiếng Anh'});
		if (checked[48] == undefined)
			topics.push({id: 48, title: 'Du học'});
		if (checked[165] == undefined)
			topics.push({id: 165, title: 'Khởi nghiệp'});
		if (checked[209] == undefined)
			topics.push({id: 209, title: 'Cách học'});
		if (checked[220] == undefined)
			topics.push({id: 220, title: 'Cuộc sống'});
		this.requestForEffectiveResource('SuggestTopics').html(this.renderView('TopicsContainerTmpl', {topics: topics}));
		
		for(var i in topics) {
			this.fetchQuestionForFollowing(url, topics, i);
		}
	},
	
	fetchQuestionForFollowing: function(url, topics, i) {
		var obj = this;
		$.getJSON(url, {q: topics[i].id}, function(ret) {
			obj.requestForEffectiveResource('SuggestTopics-'+topics[i].id).html(obj.renderView('SuggestBestQuestion', {list: ret.response.docs}));
		});
	},
	
	display: function(id) {
		var sbj = SingletonFactory.getInstance(Subject);
		var obj = this;
		obj.shuffleResult();
		obj.buildSearchItems();
		if (id == undefined)	{
			obj.getPortletPlaceholder().paintCanvas(obj.render());
		} else {
			obj.requestForEffectiveResource(id).html(obj.render());
		}
		sbj.notifyEvent("CheckMoreLessContent");
		obj.buildSearchNavigation();
		obj.buildSearchHeader();
		if (obj.core == "notification-filter" && obj.start == 0 && obj.numDocs > 0)	{
			var maxId = obj.dataResJSON[0].total_questions;
			sbj.notifyEvent("QuestionNotificationFetched", maxId);
		}
	},
	
	shuffleResult: function(){
		//watch out for this
		var count = 0;
		var result = Array();
		if(this.isShuffleResult){
			while(count < this.shuffleNo){
				var rand = Math.floor(Math.random()*this.dataResJSON.length);
				var tmp = this.dataResJSON;
				result.push(tmp[rand]);
				this.dataResJSON.splice(rand,1);
				count++;
			}
			this.dataResJSON = result;
		}
	},
	
	// done
	// return json object
	getHighlight: function(profileID, fieldName){
		if(this.highlightResJSON[profileID] == undefined || this.highlightResJSON[profileID][fieldName] == undefined){
			return null;
		}
		return this.highlightResJSON[profileID][fieldName];
	},
	
	// done
	getConfigData: function(){
		try{
			var id = this.name + "-ItemConfig" + this.pageType;
			var data = eval("(" + tmpl(id,{}) + ")");
			// iterate through json sent from server and build template arcording to view type
			var hashConfig = Array();
			// item order
			for(var key in data){
				hashConfig[key] = data[key];
			}
			return hashConfig;
		}
		catch(ex){
		}
		return null;
	},
	
	buildSearchItems: function(){
		var searchItems = Array();
		if((this.numDocs == 0 || this.dataResJSON.length == 0)){
			if(this.configData['notShowNoResult']== undefined || this.configData['notShowNoResult']== false) {
				log('show no result');
				this.numDocs = 0;
				searchItems.push(tmpl("CommonPortlet-NoResult",{}));
				this.model.children = searchItems;
				return;
			}
		}
		for(var key in this.dataResJSON){
			var curRes = this.dataResJSON[key];
			// 1 search result
			var objParam = {};
			var uiFields = this.configData['uifields'];
			for(var keyConfig in uiFields){
				for(var field in uiFields[keyConfig]){
					var templateName = uiFields[keyConfig][field];
					// get loop
					objParam[field] = this.buildSearchItemTemplate(templateName, curRes);
				}
			}
			var searchItem = $(this.buildSearchItem(objParam));
			var sbj = SingletonFactory.getInstance(Subject);
			sbj.notifyEvent("RequestCheckAnswerContent",searchItem);
			searchItems.push(searchItem);
		}
		this.model.children = searchItems;
	},
	
	// done
	buildSearchItem: function(objParam){
		var templ = this.configData['template'];
		var id = this.name + "-Item"+ templ + "-Main";
		return tmpl(id, objParam);
	},
	
	// done
	buildSearchItemTemplate: function(templateName, curRes){
		var objParam = {};
		var templ = this.configData['template'];
		var templateKey = this.name + "-Item" + templ + "-" + templateName;
		var fieldMaps = this.configData[templateName].data;
		
		for(var fieldMap in fieldMaps){
			// placeholderName => fieldMap
			var currentFieldMap = fieldMaps[fieldMap]; 
			
			var fieldRes = currentFieldMap.field;
			var type = currentFieldMap.type;
			var templateName = currentFieldMap.template;
			
			var curObjVal = curRes[fieldRes];
			var ret = null;
			
			switch(type){
				case "multiple":
					// Có nhiệm vụ lấy thông tin kiểu link, có cả id, cả content.
					// Cần truyền vào curObjVal để nó biết là cần duyệt ở cột nào.
					// array của dataJSON
					ret = this.buildSearchItemMultipleHelper(templateName, curRes, curObjVal);
					break;
				case "advanced":
					// có chữ cái cuối cùng == _1; _3...
					ret = this.buildSearchItemAdvancedHelper(templateName, curRes, fieldRes);
					break;
				case "single":
				default:
					// Chỉ lấy thông tin dạng đơn 
					// text value
					ret = curObjVal;
					break;
			}
			objParam[fieldMap] = ret;
		}
		return tmpl(templateKey, objParam);
	},
	
	// Lấy cái con cấp 2; Chắc chắn chỉ có 2 cấp
	// Cái này chuyên để lấy những thứ như id đi kèm vs cái j đó
	// để lấy link chẳng hạn.
	buildSearchItemMultipleHelper: function(templateName, curRes, curObjVal){
		var ret = $("<div></div>");
		var templ = this.configData['template'];
		var id = this.name + "-Item" + templ + "-" + templateName;
		for (var pos in curObjVal){
			var fieldMaps = this.configData[templateName].data;
			var objParam = {};
			for(var fieldMap in fieldMaps){
				try {
					// placeholderName => fieldMap
					var fieldRes = fieldMaps[fieldMap].field;
					if(curRes[fieldRes] == undefined){
						continue;
					}
					if(curRes[fieldRes][pos] == undefined){
						objParam[fieldMap] = curRes[fieldRes];
					} else {
						// REMEMBER: At first, it only has this
						objParam[fieldMap] = curRes[fieldRes][pos];
					}
				} catch (e) {
//							console.error(e);
				}
			}
			ret.append(tmpl(id, objParam));
		}
		return ret.html();
	},
	
	buildSearchItemAdvancedHelper: function(templateName, curRes, fieldRes){
		var ret = $("<div></div>");
		var templ = this.configData['template'];
		var id = this.name + "-Item" + templ + "-" + templateName;
		// đầu tiên phải chỉ định trường id là trường nào.
		var idCol = fieldRes + "_id"; 
		// lấy id của trường đó. => quy định hẳn là tên trường + _id
		var curObjVal = curRes[fieldRes];
		for (var pos in curObjVal){
			var curID = curRes[idCol][pos];
			var fieldMaps = this.configData[templateName].data;
			var objParam = {};
			for(var fieldMap in fieldMaps){
				var fieldCheck = fieldMaps[fieldMap].field;
				var curField = (fieldCheck == idCol || fieldCheck == fieldRes) ?  fieldCheck : fieldCheck + "_" + curID;
				objParam[fieldMap] = curRes[curField][pos] == null ? "" : curRes[curField][pos];
			}
			ret.append(tmpl(id, objParam));
		}
		return ret.html();
	},
	
	buildSearchNavigation: function(){
		if(this.pltParams["showNavigator"] != undefined && !this.pltParams["showNavigator"]){
			return;
		}
		if(this.configData["showNavigator"] == undefined || this.configData["showNavigator"]){
			var objParam = {};
			objParam.numDocs = this.numDocs;
			objParam.rows = this.rows;
			objParam.searchPage = this.searchPage;
			objParam.dataLength = this.dataResJSON.length;
			objParam.query = this.query;
			objParam.core = this.core;
			objParam.searchController = this.page || "Search";
			var sbj = SingletonFactory.getInstance(Subject);
			sbj.notifyEvent("FetchNavigationLink", objParam);
		}
	},
	
	buildSearchHeader: function(){
		if(this.pltParams["showSearchResult"] != undefined && !this.pltParams["showSearchResult"]){
			return;
		}
		if(this.configData["showSearchResult"] == undefined || this.configData["showSearchResult"]){
			var objParam = {};
			objParam.numDocs = this.numDocs;
			objParam.qtime = this.qtime;
			var sbj = SingletonFactory.getInstance(Subject);
			sbj.notifyEvent("FetchSearchResultNumber", objParam);
		}
	},
	
	setHighlightKeywords: function(element){
		element.find("em").addClass("bkp_search_highlight");
	},
	
	// done
	normalizeKeyword:function(keyword){
		var ret = keyword.replace("_indexed","");
		ret = ret.replace("_unindexed","");
		return ret;
	},
	
	// done
	run : function() {
		this.getDataFromServer();
	},
	
	onReloadPage: function(){
		this.onBegin();
		this.run();
	},
	
	onGetMoreResultRows: function()	{
		if (this.rows == undefined)
			this.rows = this.getRequest().getParam('rows') || 10;
		this.rows += 10;
		this.first = false;
		this.run();
	},
	
	onSearchResultChangeType: function(eventData)	{
		this.core = eventData.type || this.core || "notification-filter";
		this.page = eventData.page || this.page || 0;
		this.isShuffleResult = eventData.shuffle || this.isShuffleResult || false;
		this.rows = eventData.rows || this.rows || 10;
		this.shuffleNo = eventData.shuffleNo || this.rows;
		
		this.prepareData();
		this.run();
	},
	
	onSearchResultChangeScope: function(eventData)	{
		this.scope = eventData.scope || this.scope || "limit";
		this.page = eventData.page || this.page || 0;
		this.isShuffleResult = eventData.shuffle || this.isShuffleResult || false;
		this.rows = eventData.rows || this.rows || 10;
		this.shuffleNo = eventData.shuffleNo || this.rows;
		
		this.prepareData();
		this.run();
	},
	
	onEnd: function()	{
		this.unregisterObserver();
	}
}).implement(RenderInterface).implement(PortletInterface).implement(ObserverInterface).implement(AjaxInterface);
AnnouncementPortlet = Class.extend({
	init: function()	{
		this.name = "AnnouncementPortlet";
	},
	
	run: function()	{
		this.getPortletPlaceholder().paintCanvas(this.render());
		//this.onGetAnnouncement();
		//this.startInterval(300*1000, this.onGetAnnouncement);
	},

	onGetAnnouncement: function()	{
//		var obj = this;
//		this.onAjax('ajax', 'get-announcement', {}, 'GET', {
//			'onSuccess': function(ret)	{
//				if (ret == undefined || ret == "")
//					return;
//				obj.requestForEffectiveResource('AnnouncementContent').html(ret);
//			}
//		});
	},
	
	onEnd: function()	{
		this.stopInterval();
	}
}).implement(PortletInterface).implement(IntervalTimerInterface).implement(AjaxInterface).implement(RenderInterface);
OnlineSupportPortlet = Class.extend({
	init: function() {
		this.name = "OnlineSupportPortlet";
	},
	
	run: function() {
		this.getPortletPlaceholder().paintCanvas(this.render());
	}
}).implement(PortletInterface).implement(AjaxInterface).implement(RenderInterface);
TopicChartPortlet = Class.extend({
	init: function()	{
		this.name = "TopicChartPortlet";
	},
	
	onBegin: function() {
		this.registerObserver();
	},
	
	onEnd: function() {
		this.unregisterObserver();
	},
	
	onReloadPage: function() {
		this.run();
	},
	
	run: function() {
		var obj = this;
		var to = getWeek(new Date());
		var from = to - 16;
		var id = this.getRequest().getParam('id');
		this.onAjax('catchword', 'get-single-stats', {id: id, type: 'week', from: from, to: to}, 'get', {
			onSuccess: function(ret) {
				obj.getPortletPlaceholder().paintCanvas(obj.render());
				var data = {};
				data.cat = Array();
				data.answers = Array();
				data.questions = Array();
				data.vote = Array();
				data.delay = Array();
				var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
				
				for(var i=from;i<=to;i++)	{
					log(i/4);
					var month = months[Math.ceil(i/4.34523809524)-1];
					var w = i%4+1;
					data.cat.push(month+' W'+w);
					data.answers.push(0);
					data.questions.push(0);
					data.vote.push(0);
					data.delay.push(-1);
				}
				
				for(var i in ret.data)	{
					var cur = ret.data[i];
					data.answers[cur.week-from] = cur.answers;
					data.questions[cur.week-from] = cur.questions;
					data.vote[cur.week-from] = cur.vote;
					data.delay[cur.week-from] = cur.delay;
				}
				
				obj.data = data;
				obj.options = {
					chart: {
						renderTo: obj.name+"-Container",
						defaultSeriesType: 'line',
						marginRight: 130,
						marginBottom: 25
					},
					title: {
						text: 'Weekly data analysis for '+ret.topic,
						x: -20 //center
					},
					subtitle: {
						text: 'Auto-generated by Asking.vn Report Service',
						x: -20
					},
					xAxis: {
						categories: data.cat
					},
					yAxis: {
						title: {
							text: 'Number of activities'
						},
						plotLines: [{
							value: 0,
							width: 1,
							color: '#808080'
						}]
					},
					legend: {
						layout: 'vertical',
						align: 'right',
						verticalAlign: 'top',
						x: -10,
						y: 100,
						borderWidth: 0
					},
					tooltip: {
						formatter: function() {
							if (this.series.name == "Answers No.")
								return '<b>'+ this.series.name +'</b><br/>'+ this.x +': '+ this.y +' answers';
							if (this.series.name == "Questions No.")
								return '<b>'+ this.series.name +'</b><br/>'+ this.x +': '+ this.y +' questions';
							if (this.series.name == "Vote No.")
								return '<b>'+ this.series.name +'</b><br/>'+ this.x +': '+ this.y +' vote';
							if (this.series.name == "Avg. Waiting Time")	{
								if (this.y < 1 && this.y > 0)
									return '<b>'+ this.series.name +'</b><br/>'+ this.x +': '+ Math.ceil(this.y*24) +' hrs';
								if (this.y == -1)
									return '<b>'+ this.series.name +'</b><br/>'+ this.x +': N/A';
								return '<b>'+ this.series.name +'</b><br/>'+ this.x +': '+ this.y +' days';
							}
							return "";
						}
					},
					series: [{
						name: 'Answers No.',
						data: data.answers
					}, {
						name: 'Questions No.',
						data: data.questions
					}, {
						name: 'Vote No.',
						data: data.vote
					}, {
						name: 'Avg. Waiting Time',
						data: data.delay
					}]
				};
				
				obj.chart = new Highcharts.Chart(obj.options);
			}
		});
	},
	
	reloadOptions: function(checkedId, name, data)	{
		if (!this.requestForEffectiveResource(checkedId).is(':checked'))	{
			var series = Array();
			for(var i in this.options.series)	{
				if (this.options.series[i].name == name)	{
					continue;
				}
				series.push(this.options.series[i]);
			}
			this.options.series = series;
		} else {
			this.options.series.push({name: name, data: this.data[data]});
		}
	},
	
	onTopicAnalysisAnswerChecked: function() {
		this.reloadOptions('AnswerCheck', 'Answers No.', 'answers');
		this.chart = new Highcharts.Chart(this.options);
	},
	
	onTopicAnalysisQuestionChecked: function() {
		this.reloadOptions('QuestionCheck', 'Questions No.', 'questions');
		this.chart = new Highcharts.Chart(this.options);
	},
	
	onTopicAnalysisDelayChecked: function() {
		this.reloadOptions('DelayCheck', 'Avg. Waiting Time', 'delay');
		this.chart = new Highcharts.Chart(this.options);
	},
	
	onTopicAnalysisVoteChecked: function() {
		this.reloadOptions('VoteCheck', 'Vote No.', 'vote');
		this.chart = new Highcharts.Chart(this.options);
	}
}).implement(PortletInterface).implement(RenderInterface).implement(AjaxInterface).implement(ObserverInterface);
ContactPortlet = Class.extend({
	init: function()	{
		this.name = "ContactPortlet";
	},
	
	run: function()	{
		this.getPortletPlaceholder().drawToCanvas(this.render());
	}
}).implement(PortletInterface).implement(RenderInterface);
ErrorPortlet = Class.extend(
{
	init : function() {
		this.name = "ErrorPortlet";
		this.model = {};
		this.heading = "";
		this.errorCode = "";
		this.data = {};
	},
	
	onBegin: function()	{
		this.registerObserver();
		this.getHandledErrorCode();
		this.prepareData();
		this.prepareTemplate();
	},
	
	getHandledErrorCode: function(){
		var data = tmpl("ErrorPortlet-HandledErrorCode",{});
		return eval(data);
	},
	
	checkErrorCode: function(errorCode){
		if(errorCode == undefined || errorCode == null){
			return true;
		}
		var data = this.getHandledErrorCode();
		for(var key in data){
			if(data[key] == errorCode){
				return true;
			}
		}
		return false;
	},
	
	prepareData: function(){
		var request = SingletonFactory.getInstance(Page).getRequest();
		var params = request.getParams();
		this.errorCode = params["code"] || 404;
		this.heading = params["msg"] || this.getMsgHeading("");;
		this.data = params['content'] || this.getMsgContent("");
		if(this.checkErrorCode(this.errorCode)){
			this.heading = this.getMsgHeading(this.errorCode);
			this.data = this.getMsgContent(this.errorCode);
		}
	},
	
	prepareTemplate: function(){
		this.model.errorHeader = this.heading;
		this.model.errorContent = this.data;
	},
	
	getMsgHeading: function(errorCode){
		var errorCodeID = "ErrorCode" + errorCode;
		return this.getPrefetchData(errorCodeID, "_Heading");
	},
	
	getMsgContent: function(errorCode){
		var errorCodeID = "ErrorCode" + errorCode;
		return this.getPrefetchData(errorCodeID, "_Content");
	},
	
	getPrefetchData: function(id,type){
		try{
			return tmpl(this.name + "-" + id + type,{});
		}
		catch(ex){
			return tmpl(this.name + "-" + "ErrorCode" + type,{});
		}
	},

	run : function() {
		this.getPortletPlaceholder().drawToCanvas(this.render());
	},
	
	onEnd: function()	{
		this.unregisterObserver();
	}
}).implement(RenderInterface).implement(PortletInterface).implement(ObserverInterface);
FeedbackPortlet = Class.extend({
	init: function()	{
		this.name = "FeedbackPortlet";
	},
	
	onBegin: function()	{
		this.model = {};
		this.registerObserver();
	},
	
	run: function()	{
		this.getPortletPlaceholder().drawToCanvas(this.render());
	},
	
	onFeedbackSubmit: function()	{
		var feedback = this.requestForEffectiveResource('TextInput').val().trim();
		if (feedback == "")	{
			var obj = this.requestForEffectiveResource('Error');
			$(obj).html('Bạn vui lòng nhập thông tin phản hồi vào ô phía trên');
			return;
		}
		var email = this.requestForEffectiveResource('Email').val().trim();
		var obj = this;
		this.onAjax('ajax', 'send-feedback', {'content': feedback, 'email': email}, 'POST', {
			'onSuccess': function(ret)	{
				var subject = SingletonFactory.getInstance(Subject);
				subject.notifyEvent('NotifyMessage', 'Cảm ơn bạn đã đóng góp cho hệ thống! Chúng tôi sẽ nghiên cứu phản hồi của bạn và cải thiện hệ thống cho phù hợp.');
				var request = new Request('Home');
				subject.notifyEvent('RequestRoute', request);
			},
			'onFailure': function(message)	{
				var error = obj.requestForEffectiveResource('Error');
				$(error).html(message);
			}
		});
	},
	
	onEnd: function()	{
		this.unregisterObserver();
	}
}).implement(PortletInterface).implement(RenderInterface).implement(ObserverInterface).implement(AjaxInterface);
FooterPortlet = Class.extend({
	init:function() {
		this.name = "FooterPortlet";
		this.ids = new Array("TermOfUse","Privacy","Tutorial","AboutUs");
		this.activeId = undefined; 
	},
	
	requestForResource: function(resourceName){
		var app = SingletonFactory.getInstance(Application);
		var rm = app.getResourceManager();
		return rm.requestForResource(this.name,resourceName);
	},
	
	onReloadPage: function()	{
		for( var i=0; i < this.ids.length; i++ ){
			if(this.requestForEffectiveResource(this.ids[i]) != undefined ){
				if(this.requestForEffectiveResource(this.ids[i]).hasClass("footeritem_active")){
					this.requestForEffectiveResource(this.ids[i]).removeClass("footeritem_active");
				}
			}
		}
	},
	
	setActive: function(id){
		this.activeId = id;
		for( var i=0; i < this.ids.length; i++ ){
			if(this.requestForEffectiveResource(this.ids[i]) != undefined ){
				if(this.requestForEffectiveResource(this.ids[i]).hasClass("footeritem_active")){
					this.requestForEffectiveResource(this.ids[i]).removeClass("footeritem_active");
				}
			}
		}
		if(this.requestForEffectiveResource(id) != undefined ){
			this.requestForEffectiveResource(id).addClass("footeritem_active");
		}
	},

	run: function() {
		this.getPortletPlaceholder().drawToCanvas(this.render());
		if(this.activeId != undefined){
			this.setActive(this.activeId);
		}
	}
}).implement(RenderInterface).implement(PortletInterface);
IntroducePortlet = Class.extend({
	init: function()	{
		this.name = "IntroducePortlet";
	},
	
	onBegin: function()	{
		this.model = {};
		this.registerObserver();
	},
	
	onSubscribeHomeButtonClick: function() {
		var obj = this;
		var email = this.requestForEffectiveResource('Email').val();
		this.onAjax('ajax', 'subscribe', {email: email}, 'post', {
			onSuccess: function(ret)	{
				obj.requestForEffectiveResource('Email').val('');
				var subject = SingletonFactory.getInstance(Subject);
				subject.notifyEvent('NotifyGlobal', 'Bạn đã đăng ký nhận tin thành công');
			},
			onFailure: function(msg)	{
				var subject = SingletonFactory.getInstance(Subject);
				subject.notifyEvent('NotifyError', msg);
			}
		});
	},
	
	onEnd: function() {
		this.unregisterObserver();
	},
	
	onLoginSuccess: function() {
		var subject = SingletonFactory.getInstance(Subject);
		subject.notifyEvent('RequestRoute', new Request('Home'));
	},

	run: function()	{
		this.model.login = SingletonFactory.getInstance(Application).getSystemProperties().get('user.login');
		this.getPortletPlaceholder().drawToCanvas(this.render());
	}
}).implement(PortletInterface).implement(RenderInterface).implement(ObserverInterface).implement(AjaxInterface);
GmailInvitation = Class.extend({
	
	init: function()	{
		this.scope = "https://www.google.com/m8/feeds";
		this.contactsService = new google.gdata.contacts.ContactsService('BKProfile-GmailContactFeed-1.0');
	},
	
	setCallback: function(callback)	{
		this.callback = callback;
	},
	
	checkLogin: function()	{
		return (google.accounts.user.checkLogin(this.scope));
	},
	
	logMeOut: function(){
		google.accounts.user.logout(function() {}, this.scope);
	},
	
	authenticate: function()	{
//		if (google.accounts.user.checkLogin(this.scope))	{
//			this.onAuthReady();
//			return;
//		}
		var w = 600;
		var h = 450;
		var left = (screen.width/2)-(w/2);
		var top = (screen.height/2)-(h/2);
		window.open('invite.html', 'authWindow', "status = 0, height = "+h+", width = "+h+", resizable = 0, left = "+left+", top = "+top);
	},
	
	feedContact: function(maximum)	{
		var contactsFeedUri = 'https://www.google.com/m8/feeds/contacts/default/full';
		var query = new google.gdata.contacts.ContactQuery(contactsFeedUri);
		  
		// Set the maximum of the result set to be 10
		query.setMaxResults(maximum);
		
		var obj = this;
		this.contactsService.getContactFeed(query, function(result) {obj.callback(result);}, function() {});
	}
});

InvitationPortlet = Class.extend({
	init: function()	{
		this.name = "InvitationPortlet";
	},
	
	onBegin: function()	{
		this.registerObserver();
		this.currentMaxContacts = 350;
	},
	
	onSendInviteButtonClick: function(eventData)	{
		var email = eventData.email;
		var origin = eventData.origin.target;
		var plhd = $(origin).parent();
		plhd.html('<img class="invite-ajax-loader" src="resource/images/ajax-loader-1.gif">');
		this.onAjax('invitation', 'send-invitation', {'email': email}, 'POST', {
			'onSuccess': function()	{
				$(plhd).html('<strong class="InvitationSent">Đã gửi lời mời</strong>');
			},
			
			'onFailure': function()	{
				$(plhd).html('<div class="errorMsg">Gửi thất bại!</div>');
			}
		});
	},
	
	onFeedContacts: function(result)	{
		var entries = result.feed.entry;
		var contacts = Array();
		var emails = Array();
		var names = Array();
		for (var i = 0; i < entries.length; i++) {
			var contact = {};
			var contactEntry = entries[i];
			var photoLink = contactEntry.getContactPhotoLink();
			if (photoLink != undefined)	{
				photo = photoLink.getHref();
			}
			else
				photo = "resource/images/unknown.png";
			if (contactEntry.getTitle() && contactEntry.getTitle().getText())	{
				contact.name = contactEntry.getTitle().getText();
			} else {
				contact.name = " ";
			}
			contact.photo = photo;
			contact.emails = Array();
		    var emailAddresses = contactEntry.getEmailAddresses();
		    if (emailAddresses.length == 0)
		    	continue;
		    var emailAddress = emailAddresses[0].address;
		    if (emailAddress == this.currentEmail)	{
		    	continue;
		    }
		    names.push(contact.name);
		    emails.push(emailAddress);
		    contact.email = emailAddress;
		    contacts.push(contact);
		}
		var existing = Array();
		var obj = this;
		this.onAjax('invitation', 'get-invite-users-from-emails', {'emails': emails.join(','), names: names.join(',')}, 'POST', {
			'onSuccess': function(ret)	{
				obj.requestForEffectiveResource('Processing').hide();
				var exist = ret.existing;
				
				for(var i=0;i<exist.length;i++)	{
					var email = exist[i].email;
					//remove contacts which exists in our system
					for(var j in contacts)	{
						var contact = contacts[j];
						if (contact.email == email)	{
							contacts.splice(j, 1);
							break;
						}
					}
					existing.push(exist[i]);
				}
				
				obj.currentContacts = contacts;
				obj.requestForEffectiveResource('ExistingContactsFeed').html(obj.renderView('ExistingContacts', {'contacts': existing}));
				obj.requestForEffectiveResource('ContactsFeed').html(obj.renderView('Contacts', {'contacts': contacts}));
				var target = obj.requestForEffectiveResource('EmailFilter');
				var subject = SingletonFactory.getInstance(Subject);
				subject.notifyEvent('AttachFocusDetection', {'target': target, 'defaultValue': 'Nhập tên/email để tìm kiếm'});
				
				//filtering function
				$(target).keyup(function()	{
					obj.onShowMoreExistingContacts();
					var val = $(target).val();
					for(var i=0;i<obj.currentContacts.length;i++)	{
						if (obj.currentContacts[i].name.indexOf(val) == -1 && obj.currentContacts[i].email.indexOf(val) == -1)	{
							$('div[contactID="'+i+'"]').hide();
						} else {
							$('div[contactID="'+i+'"]').show();
						}
					}
				});
			}
		});
	},
	
	feed: function()	{
		this.invitationImpl.feedContact(this.currentMaxContacts);
		this.currentMaxContacts += 50;
	},
	
	onShowMoreExistingContacts: function() {
		var btn = this.requestForEffectiveResource('ShowMore');
		btn.siblings('.hidden').removeClass('hidden'); 
		btn.addClass('hidden');
	},
	
	onAuthSubAuthenticateButtonClick: function()	{
		this.invitationImpl.authenticate();
		this.startInterval(500, function() {
			if (this.invitationImpl.checkLogin())	{
				//this.requestForEffectiveResource('Title').hide();
				this.requestForEffectiveResource('AuthStep').hide();
				this.requestForEffectiveResource('ContactsFeed').hide();
				this.requestForEffectiveResource('Processing').show();
				this.feed();
				this.stopInterval();
			}
		});
	},
	
	onNextInvitePage: function(eventData) {
		if (eventData != undefined && eventData.follow)	{
			var uid = Array();
			this.requestForEffectiveResource('ExistingContactsFeed').find('input[type=checkbox]').each(function() {
				var $this = $(this);
				if ($this.is(':checked'))	{
					uid.push($this.attr('uid'));
				}
			});
			if (uid.length > 0) {
				var obj = this;
				var subject = SingletonFactory.getInstance(Subject);
				subject.notifyEvent('AjaxBegan');
				this.onAjax('user-ajax', 'follow-people', {ids: uid.join(',')}, 'post', {
					onSuccess: function(ret)	{
						subject.notifyEvent('NotifyGlobal', 'Bạn đã theo dõi '+uid.length+' người');
						obj.nextStep();
					}
				});
			} else {
				this.nextStep();
			}
		} else {
			this.nextStep();
		}
	},
	
	onSelectAllPeopleInvite: function() {
		if (this.requestForEffectiveResource('SelectAll').is(':checked'))	{
			this.requestForEffectiveResource('ExistingContactsFeed').find('input[type=checkbox]').attr('checked', 'checked');
		} else {
			this.requestForEffectiveResource('ExistingContactsFeed').find('input[type=checkbox]').removeAttr('checked');
		}
	},
	
	nextStep: function() {
		this.requestForEffectiveResource('ExistingContactsFeed').hide();
		this.requestForEffectiveResource('ContactsFeed').show();
	},
	
	run: function()	{
		this.model = {};
		this.getPortletPlaceholder().paintCanvas(this.render());
		
		var e = document.createElement('script'); e.async = true;
	    e.src = document.location.protocol + '//www.google.com/jsapi';
	    $("#script-root").append(e);
	    
	    e = document.createElement('script'); e.async = true;
	    e.src = document.location.protocol + '//www.google.com/uds/?file=gdata&amp;v=1.x';
	    $("#script-root").append(e);
	    
	    e = document.createElement('script'); e.async = true;
	    e.src = document.location.protocol + '//www.google.com/uds/api/gdata/1.10/bb5c7bea9d0f750980b0c50aeb221391/core,mediarss,opensearch,atom,app,gdata,contacts,default.I.js';
	    $("#script-root").append(e);
	    
		this.requestForEffectiveResource('AuthStep').html(this.renderView('Authenticate', {}));

		var obj = this;
		var interval = setInterval(function() {
			if (google != undefined && google.gdata != undefined && google.accounts != undefined) {
				clearInterval(interval);
				obj.invitationImpl = new GmailInvitation();
				obj.invitationImpl.setCallback(function(result) {
					var subject = SingletonFactory.getInstance(Subject);
					subject.notifyEvent('FeedContacts', result);
				});
			}
		}, 500);
		/*var loggedIn = SingletonFactory.getInstance(Application).getSystemProperties().get('user.login');
		if (loggedIn == 1)	{
			var obj = this;
			this.onAjax('user-ajax', 'get-user-email', {}, 'GET', {
				'onSuccess': function(ret)	{
					obj.currentEmail = ret;
				}
			});
		}*/
	},
	
	onEnd: function()	{
		this.unregisterObserver();
		this.stopInterval();
	}
}).implement(PortletInterface).implement(RenderInterface).implement(AjaxInterface).implement(ObserverInterface).implement(IntervalTimerInterface);
InviteLinkPortlet = Class.extend({
	init: function()	{
		this.name = "InviteLinkPortlet";
	},
	
	onBegin: function()	{
		this.registerObserver();
	},
	
	onEnd: function()	{
		this.unregisterObserver();
	},
	
	onSendBriefInvitation: function(eventData) {
		var obj = this;
		var plhd = eventData.target;
		$(plhd).parent().html('<img class="invite-ajax-loader" src="resource/images/ajax-loader-1.gif">');
		this.onAjax('invitation', 'send-invitation', {'email': eventData.email}, 'POST', {
			'onSuccess': function()	{
				obj.run();
			}
		});
	},
	
	run: function()	{
		var obj = this;
		this.onAjax('user-ajax', 'fetch-contacts-to-invite', {}, 'get', {
			onSuccess: function(ret) {
				obj.getPortletPlaceholder().paintCanvas(obj.render());
				if (ret.length == 0)	{
					obj.requestForEffectiveResource('Container').html(obj.renderView('Link', {}));
				} else {
					var people = Array();
					for(var j=0;j<2;j++)	{
						var i = Math.floor(Math.random()*ret.length);
						people.push(ret[i]);
						ret.splice(i, 1);
					}
					obj.requestForEffectiveResource('Container').html(obj.renderView('People', {people: people}));
				}
			}
		});
	}
}).implement(PortletInterface).implement(RenderInterface).implement(AjaxInterface).implement(ObserverInterface);
EventLinkPortlet = Class.extend({
	init: function()	{
		this.name = "EventLinkPortlet";
	},
	
	onBegin: function()	{
		this.model = {};
	},

	run: function()	{
		this.getPortletPlaceholder().paintCanvas(this.render());
	}
}).implement(PortletInterface).implement(RenderInterface);
FacebookLikeBoxPortlet = Class.extend({
	init: function()	{
		this.name = "FacebookLikeBoxPortlet";
	},
	
	run: function()	{
		this.getPortletPlaceholder().paintCanvas(this.render());
		(function(d, s, id) {
		  var js, fjs = d.getElementsByTagName(s)[0];
		  if (d.getElementById(id)) {return;}
		  js = d.createElement(s); js.id = id;
		  js.src = "//connect.facebook.net/en_US/all.js#xfbml=1&appId=251988771483162";
		  fjs.parentNode.insertBefore(js, fjs);
		}(document, 'script', 'facebook-jssdk'));
	}
}).implement(PortletInterface).implement(RenderInterface);
LinksPortlet = Class.extend({
	init: function()	{
		this.name = "LinksPortlet";
	},
	
	onBegin: function()	{
		this.model = {};
	},

	run: function()	{
		this.getPortletPlaceholder().drawToCanvas(this.render());
	}
}).implement(PortletInterface).implement(RenderInterface);
StaticContentShortPortlet = Class.extend({
	init:function() {
		this.name = "StaticContentShortPortlet";
		this.ids = new Array("AboutUsShort");
	},
	
	displayContent: function(){
		var request = this.getRequest();
		var container = SingletonFactory.getInstance(PortletContainer);
		var footer = container.getPortletMetaByName("FooterPortlet").portlet;
		var id = request.getParam("page");
		for( var i=0; i<this.ids.length; i++ ){
			var res = this.requestForEffectiveResource(this.ids[i]);
			if(res != undefined && ! res.hasClass("doNotDisplay")){
				res.addClass("doNotDisplay");
			}
		}
		this.requestForEffectiveResource(id).removeClass("doNotDisplay");
		footer.setActive(id);
	},
	
	onReloadPage: function(){
		this.displayContent();
	},
	
	run: function() {
		this.getPortletPlaceholder().drawToCanvas(this.render());
		this.displayContent();
	}
}).implement(RenderInterface).implement(PortletInterface);
StaticContentPortlet = Class.extend({
	init:function() {
		this.name = "StaticContentPortlet";
		this.ids = new Array("History", "AboutUs","ImportantScoreIntro","BKProfileUseAskingAPI","FromBKP", "AboutBKProfile", "VersionOfBKprofile","ArticleIntroduce", "RecoverError", "Tutorial", "Faq", "TermOfUse", "Privacy", "Architecture");
	},
	
	displayContent: function(){
		var request = this.getRequest();
		var id = request.getParam("page");
		for( var i=0; i<this.ids.length; i++ ){
			var res = this.requestForEffectiveResource(this.ids[i]);
			if(res != undefined && ! res.hasClass("doNotDisplay")){
				res.addClass("doNotDisplay");
			}
		}
		this.requestForEffectiveResource(id).removeClass("doNotDisplay");
	},
	
	onReloadPage: function(){
		this.displayContent();
	},
	
	run: function() {
		this.getPortletPlaceholder().drawToCanvas(this.render());
		this.displayContent();
	}
}).implement(RenderInterface).implement(PortletInterface);
IntroduceNavPortlet = Class.extend({
	init:function() {
		this.name = "IntroduceNavPortlet";
	},
	
	onReloadPage: function(){
		this.run();
	},
	
	run: function() {
		this.getPortletPlaceholder().paintCanvas(this.render());
		//$('p[page="'+this.getRequest().getParam('page')+'"]').hide();
	}
}).implement(RenderInterface).implement(PortletInterface);
SlidePortlet = Class.extend({
	init: function()	{
		this.name = "SlidePortlet";
	},
	
	run: function()	{
		var list = Array();
		list.push({img: 'resource/images/spring/register.png', title: 'Đăng ký thành viên', desc: 'Đăng ký thành viên để tham gia chia sẻ tri thức'});
		list.push({img: 'resource/images/spring/qa.png', title: 'Hỏi - Đáp', desc: 'Đặt câu hỏi và trả lời những vấn đề quan tâm'});
		list.push({img: 'resource/images/spring/follow.png', title: 'Follow', desc: 'Follow những thành viên mình quan tâm'});
//		list.push({img: 'resource/images/spring/register.png', title: 'Kết nối', desc: 'Gửi tin nhắn cho thành viên khác'});
		this.model = {list: list};
		this.getPortletPlaceholder().paintCanvas(this.render());
		this.slideshow();
	},
	
	slideshow: function() {
		this.current = 0;
		this.show();
		this.startInterval(5000, this.show);
	},
	
	show: function() {
		$('.box_skitter li').hide();
		var cur = $('.box_skitter ul li')[this.current];
		$(cur).fadeIn(3000);
		this.current++;
		if (this.current >= $('.box_skitter li').length)
            this.current = 0;
	},
	
	onEnd: function() {
		this.stopInterval();
	}
}).implement(PortletInterface).implement(RenderInterface).implement(IntervalTimerInterface);
StatsPortlet = Class.extend({
	init: function()	{
		this.name = "StatsPortlet";
	},
	
	run: function()	{
		this.getPortletPlaceholder().drawToCanvas(this.render());
		this.fetch();
	},
	
	fetch: function()	{
		var obj = this;
		this.onAjax('ajax', 'count-stats', {}, 'GET', {
			'onSuccess': function(ret)	{
				obj.requestForEffectiveResource('UserTotal').html(ret.user);
				obj.requestForEffectiveResource('QuestionTotal').html(ret.question);
				obj.requestForEffectiveResource('AnswerTotal').html(ret.answer);
				obj.requestForEffectiveResource('CatchwordTotal').html(ret.catchword);
			}
		});
	},
	
	onEnd: function()	{
	}
}).implement(PortletInterface).implement(AjaxInterface).implement(RenderInterface);
UnsubscribePortlet = Class.extend({
	init: function()	{
		this.name = "UnsubscribePortlet";
	},

	onBegin: function()	{
		this.model = {};
		this.registerObserver();
	},
	
	onEnd: function() {
		this.unregisterObserver();
	},
	
	onReloadPage: function() {
		this.run();
	},
	
	onConfirmUnsubscribe: function() {
		var obj = this;
		var email = this.getRequest().getParam('e');
		var code = this.getRequest().getParam('c');
		this.onAjax('ajax', 'unsubscribe', {email: email, code: code}, 'post', {
			onSuccess: function(ret)	{
				obj.requestForEffectiveResource('Container').html(obj.renderView('ConfirmSuccess', {}));
			},
			onFailure: function(msg)	{
				obj.requestForEffectiveResource('Error').html(msg);
			}
		});
	},
	
	onSendUnsubscribeCodeButtonClick: function() {
		var email = this.requestForEffectiveResource('Email').val();
		var obj = this;
		this.onAjax('ajax', 'send-unsubscribe-email', {email: email}, 'post', {
			onSuccess: function(ret)	{
				var subject = SingletonFactory.getInstance(Subject);
				subject.notifyEvent('RequestRoute', new Request('Home'));
				subject.notifyEvent('NotifyGlobal', 'Email xác nhận đã được gửi đến hòm mail của bạn');
			},
			onFailure: function(msg)	{
				obj.requestForEffectiveResource('Error').html(msg);
			}
		});
	},
	
	run: function()	{
		var obj = this;
		this.getPortletPlaceholder().paintCanvas(this.render());
		var email = this.getRequest().getParam('e');
		var code = this.getRequest().getParam('c');
		var d = this.getRequest().getParam('do');
		if (d == 'resend')	{
			this.requestForEffectiveResource('Container').html(this.renderView('SendMail', {}));
			return;
		}
		this.onAjax('ajax', 'is-unsubscribe-code-valid', {email: email, code: code}, 'post', {
			onSuccess: function(ret)	{
				obj.requestForEffectiveResource('Container').html(obj.renderView('Confirm', {email: email}));
			},
			onFailure: function(msg)	{
				obj.requestForEffectiveResource('Container').html(obj.renderView('ErrorToken', {}));
			}
		});
	}
}).implement(PortletInterface).implement(RenderInterface).implement(AjaxInterface).implement(ObserverInterface);
SubscribePortlet = Class.extend({
	init: function()	{
		this.name = "SubscribePortlet";
	},

	onBegin: function()	{
		this.model = {};
		this.registerObserver();
	},
	
	onEnd: function() {
		this.unregisterObserver();
	},
	
	onReloadPage: function() {
		this.run();
	},
	
	onSystemPropertyChanged: function(eventData)	{
		if (eventData == 'user.login')	{
			this.run();
		}
	},
	
	onSubscribeButtonClick: function() {
		var obj = this;
		var email = this.requestForEffectiveResource('Email').val();
		this.onAjax('ajax', 'subscribe', {email: email}, 'post', {
			onSuccess: function(ret)	{
				obj.requestForEffectiveResource('Email').val('');
				var subject = SingletonFactory.getInstance(Subject);
				subject.notifyEvent('NotifyGlobal', 'Bạn đã đăng ký nhận tin thành công');
			},
			onFailure: function(msg)	{
				var subject = SingletonFactory.getInstance(Subject);
				subject.notifyEvent('NotifyError', msg);
			}
		});
	},
	
	run: function()	{
		var obj = this;
		var login = SingletonFactory.getInstance(Application).getSystemProperties().get('user.login');
		if (login == 1)	{
			this.onAjax('user-ajax', 'is-subscribe', {}, 'post', {
				onSuccess: function(ret)	{
					if (!ret)	{
						obj.getPortletPlaceholder().paintCanvas(obj.render());
					} else {
						obj.getPortletPlaceholder().paintCanvas("");
					}
				}
			});
		} else {
			this.getPortletPlaceholder().paintCanvas(this.render());
		}
	}
}).implement(PortletInterface).implement(RenderInterface).implement(AjaxInterface).implement(ObserverInterface);
FeedbackListPortlet = StatsPortlet.extend({
	init: function()	{
		this.name = "FeedbackListPortlet";
		this.interval = 600000;
	},
	
	run: function()	{
		this.fetch();
		this.startInterval(this.interval, this.fetch);
	},
	
	fetch: function()	{
		var obj = this;
		obj.getPortletPlaceholder().paintCanvas(obj.render());
		this.onAjax('ajax', 'get-feedback-list', {}, 'GET', {
			'onSuccess': function(ret)	{
				var model = {};
				model.feedbacks = ret;
				obj.requestForEffectiveResource('ContentPlaceholder').html(obj.renderView('Content', model));
			}
		});
	}
}).implement(PortletInterface).implement(AjaxInterface).implement(RenderInterface).implement(IntervalTimerInterface);;
AllTopicsPortlet = Class.extend({
	init: function()	{
		this.name = "AllTopicsPortlet";
	},
	
	onBegin: function() {
		this.registerObserver();
	},
	
	onEnd: function() {
		this.unregisterObserver();
	},
	
	onNewTopicAdded: function(eventData) {
		this.getPortletPlaceholder().drawToCanvas(this.renderView('TopicItem', eventData));
	},
	
	run: function(name)	{
		var obj = this;
		obj.getPortletPlaceholder().paintCanvas(obj.render());
		
		this.onAjax('catchword', 'get-all-catchwords', {}, 'GET', {
			'onSuccess': function(ret)	{
				var maxLength = 23;
				var map = {};
				for(var i in ret)	{
					ret[i].catchWordTitle = ret[i].catchWord;
					if (ret[i].catchWord.length > maxLength)	{
						var trimmed = ret[i].catchWord.substr(0, maxLength - 3);
						var lastWordIndex = trimmed.lastIndexOf(' ');
						if (lastWordIndex != -1)	{
							trimmed = trimmed.substr(0, lastWordIndex);
						}
						ret[i].catchWord = trimmed+"...";
					}
					if (map[ret[i].contextId] == undefined) {
						map[ret[i].contextId] = {};
						map[ret[i].contextId].catchwords = Array();
						map[ret[i].contextId].context = ret[i].context;
					}
					map[ret[i].contextId].catchwords.push(ret[i]);
				}
				
				obj.requestForEffectiveResource('ContentPlaceholder').html(obj.renderView('Topics', {catchwords: map}));
				
				obj.map = map;
				obj.requestForEffectiveResource('ContextPlaceholder').html(obj.renderView('Contexts', {contexts: map}));
			}
		}, true, 300000);
	},
	
	refreshCatchwords: function() {
		var catchwords = Array();
		var obj = this;
		this.requestForEffectiveResource('ContextPlaceholder').find('input').each(function() {
			if ($(this).is(':checked'))	{
				var cid = $(this).attr('cid');
				for(var i in obj.map[cid].catchwords)	{
					catchwords.push(obj.map[cid].catchwords[i]);
				}
			}
		});
		obj.requestForEffectiveResource('ContentPlaceholder').html(obj.renderView('Topics', {catchwords: catchwords}));
	},
	
	onSelectAllContexts: function() {
		this.requestForEffectiveResource('ContextPlaceholder').find('input[type=checkbox]').attr('checked', 'checked');
		this.refreshCatchwords();
	},
	
	onDeselectAllContexts: function() {
		this.requestForEffectiveResource('ContextPlaceholder').find('input[type=checkbox]').removeAttr('checked');
		this.refreshCatchwords();
	},
	
	onContextSelectionChanged: function() {
		this.refreshCatchwords();
	}
}).implement(PortletInterface).implement(RenderInterface).implement(AjaxInterface).implement(ObserverInterface);
CatchWordBrowserPortlet = Class.extend({
	init: function()	{
		this.name = "CatchWordBrowserPortlet";
	},
	
/**	onBegin: function()	{
		this.registerObserver();
	},
	
	onReloadPage: function()	{
		this.checkActive();
	},
	
	checkActive: function()	{
		var request = this.getRequest();
		var curId = request.getParam('id');
		this.requestForEffectiveResource('ContentPlaceholder').find('[tid]').each(function(){
			var tid = $(this).attr('tid');
			if (tid == curId)	{
				$(this).addClass('active');
			} else {
				$(this).removeClass('active');
			}
		});
	},*/
	
	run: function()	{
		var obj = this;
		this.onAjax('catchword', 'browse-catch-word', {}, 'GET', {
			'onSuccess': function(ret)	{
				obj.model = {};
				obj.model.catchwords = Array();
				for (var i in ret)	{
					obj.model.catchwords.push(ret[i]);
				}

				obj.getPortletPlaceholder().paintCanvas(obj.render());
				obj.requestForEffectiveResource('ContentPlaceholder').find('ul:first').addClass('first');
				obj.requestForEffectiveResource('ContentPlaceholder').find('ul:last').addClass('last');
				obj.requestForEffectiveResource('ContentPlaceholder').find('ul:last').append('<li class="more"><a style="font-weight: normal; color: #069" href="#!page/AllTopics">Xem tất cả</a></li>');
				//obj.checkActive();
			}
		}, true, 300000);
	},
	
/**	onEnd: function()	{
		this.unregisterObserver();
	}*/
}).implement(PortletInterface).implement(RenderInterface).implement(AjaxInterface)/*.implement(ObserverInterface)*/;
CatchWordIntroPortlet = CatchWordBrowserPortlet.extend({
	init: function()	{
		this.name = "CatchWordIntroPortlet";
	},
	
	run: function()	{
		var obj = this;
		this.onAjax('catchword', 'browse-catch-word', {}, 'GET', {
			'onSuccess': function(ret)	{
				obj.model = {};
				obj.model.catchwords = Array();
				for (var i in ret)	{
					obj.model.catchwords.push(ret[i]);
				}

				obj.getPortletPlaceholder().paintCanvas(obj.render());
				obj.requestForEffectiveResource('ContentPlaceholder').find('ul:first').addClass('first');
				obj.requestForEffectiveResource('ContentPlaceholder').find('ul:last').addClass('last');
				obj.requestForEffectiveResource('ContentPlaceholder').find('ul:last').append('<li class="more"><a style="font-weight: normal; color: #069" href="#!page/AllTopics">Xem tất cả</a></li>');
			}
		}, true, 300000);
	}
}).implement(PortletInterface).implement(RenderInterface).implement(AjaxInterface)/*.implement(ObserverInterface)*/;
SmallTopicCreatePortlet = Class.extend({
	init : function() {
		this.name = "SmallTopicCreatePortlet";
	},
	
	onBegin: function() {
		this.registerObserver();
	},
	
	onEnd: function() {
		this.unregisterObserver();
	},
	
	onTopicNameFocus: function() {
		this.requestForEffectiveResource('DesContainer').show();
	},
	
	onAddNewTopic: function(){
		var obj = this;
		var topicName = this.requestForEffectiveResource('Name').val();
		var topicDes = this.requestForEffectiveResource('Des').val();
		var sbj = SingletonFactory.getInstance(Subject);
		this.onAjax('catchword', 'add-new-topic', {topicName: topicName, topicDes: topicDes}, 'post', {
			onSuccess: function(ret){
				sbj.notifyEvent("NotifyGlobal","Thêm thành công");
				obj.requestForEffectiveResource('Name').val('');
				obj.requestForEffectiveResource('Des').val('');
				obj.requestForEffectiveResource('DesContainer').hide();
				sbj.notifyEvent("NewTopicAdded", {'value': ret, 'txt':topicName});
			},
			onFailure: function(){
				sbj.notifyEvent("NotifyGlobal","Thêm thất bại");
			}
		});
	},
	
	run : function() {
		this.getPortletPlaceholder().paintCanvas(this.render());
	}	
}).implement(RenderInterface).implement(PortletInterface).implement(ObserverInterface).implement(AjaxInterface);
TopicCreatePortlet = Class.extend({
	init : function() {
		this.name = "TopicCreatePortlet";
		this.model = {};
		this.template = "";
		this.topics = null;
		this.app = SingletonFactory.getInstance(Application);
		this.root = this.app.getSystemProperties().get("host.root");
		this.addedTopics = null;
		this.topicMap = Array();
		this.topicAvaiContextCommit = Array();
		this.topicNewContextCommit = Array();
	},
	
	onBegin: function()	{
		this.registerObserver();
		this.template = $(tmpl("CommonPortlet-TopicNew",{}));
	},
	
	onNewTopicAdded: function(eventData){
		var topicID = eventData.name;
		var topicDesID = eventData.des;
		
		var topicContent = $("#" + topicID).val().trim();
		var topicDes = $("#" + topicDesID).val().trim();
		
		if(topicContent == "" || topicDes == ""){
			alert("Chưa nhập đủ chủ đề và chi tiết chủ đề");
			return;
		}
		
		// đã có
		var objParam = {};
		objParam.content = topicContent;
		if(this.topicMap[objParam.content]){
			alert("Đã có chủ đề này.");
			return;
		}
		this.topicMap[objParam.content] = true;
		var template = tmpl("CommonPortlet-Topic",objParam);
		$("#commonCreatedTopics").append(template);
		objParam = {};
		objParam.topicName = topicContent;
		objParam.topicDes = topicDes;
		this.topicAvaiContextCommit.push(objParam);
	
		// reset
		$("#" + topicID).val("");
		$("#" + topicDesID).val("");
	},
	
	prepareTopics: function(){
		if(SingletonFactory.getInstance(Application).getSystemProperties().get("memcached.topics") == undefined){
			this.getAjaxAllTopics();
		}
	},
	
	getAjaxAllTopics: function(){
		var curPlt = this;
		this.onAjax('catchword', 'get-all-catchwords', {}, 'get', {
			onSuccess: function(ret){
				curPlt.preparedAvaiTopics (ret);
				curPlt.topics = ret;
				SingletonFactory.getInstance(Application).getSystemProperties().set("memcached.topics",ret);
			}
		});
		this.topics = curPlt.topics;
	},
	
	preparedAvaiTopics: function(arr){
		for ( var key in arr) {
			var curObj = arr[key];
			content = curObj['catchWord'];
			this.topicMap[content] = true;
		}
	},
	
	buildTopics: function(arr){
		var result = $("<div><div></div></div>");
		for ( var key in arr) {
			var curObj = arr[key];
			var newTp = $("<option value='"+curObj['id']+"'>"+curObj['catchWord']+"</option>");
			result.children().append(newTp);
		}
		return result.children();
	},
	
	onNewTopicConfirmed: function(){
		var curPlt = this;
		this.numCount = this.topicAvaiContextCommit.length;
		this.done = 0;
		for(var key in this.topicAvaiContextCommit){
			var curObj = this.topicAvaiContextCommit[key]; 
			var sbj = SingletonFactory.getInstance(Subject);
			this.onAjax('catchword', 'add-new-topic', curObj, 'post', {
				onSuccess: function(ret){
					if(!isNaN(ret)){
						curPlt.done++;
						sbj.notifyEvent("NotifyGlobal","Thêm thành công");
						sbj.notifyEvent("CommitTopicSuccess", {'value': ret, 'txt':curObj.topicName});
					}
				},
				onFailure: function(){
					sbj.notifyEvent("NotifyGlobal","Thêm thất bại");
				}
			});
		}
	},
	
	onCommitTopicSuccess: function()	{
		if(this.done < this.numCount){
			return;
		}
		var sbj = SingletonFactory.getInstance(Subject);
		var rq = SingletonFactory.getInstance(Page).getRequest();
		var params = rq.getParams();
		var page = params["pageCallBack"] || "Home";
		var needParam = params["needParam"] || {};
		var paramVal = params["paramVal"] || null;
		var paramName = params["paramName"] || null;
		var request = null;
			
		if(eval(needParam)){
			if(paramVal != null && paramName!= null){
				var obj = {};
				obj[paramName] = paramVal;
				request = new Request(page,"",obj);
			} else {
				request = new Request(page,"",{});
			}
		} else {
			request = new Request("Home","",{});
		}

		sbj.notifyEvent('RequestRoute', request);
	},
	
	run : function() {
		this.prepareTopics();
		this.getPortletPlaceholder().drawToCanvas(this.template);
	},
	
	onEnd: function()	{
		this.unregisterObserver();
	}
}).implement(RenderInterface).implement(PortletInterface).implement(ObserverInterface).implement(AjaxInterface);
TopicCreatePortletStandalone = TopicCreatePortlet.extend({
	init: function()	{
		this._super();
		this.name = "TopicCreatePortletStandalone";
	},
	
	onShowTopicCreatePopup: function(eventData)	{
		this.commitCallback = eventData.commitcallback;
		this.callback = eventData.callback;
		var subject = SingletonFactory.getInstance(Subject);
		subject.notifyEvent('ShowPopup', {id: 'TopicCreatePortletStandalone', 'title': 'Thêm chủ đề mới', 'content': this.template.html()});
	},
	
	onCommitTopicSuccess: function(eventData)	{
		var subject = SingletonFactory.getInstance(Subject);
		var commitCb = this.commitCallback;
		var cb = this.callback;
		subject.notifyEvent(commitCb, eventData);
		if (this.done < this.numCount)
			return;
		subject.notifyEvent('PopupRemove', {id: 'TopicCreatePortletStandalone'});
		subject.notifyEvent(cb);
	}
}).implement(PortletInterface).implement(RenderInterface).implement(ObserverInterface);
TopicMainPortlet = Class.extend({
	init: function()	{
		this.name = "TopicMainPortlet";
	},
	
	onReloadPage: function()	{
		this.run();
	},
	
	run: function()	{
		var subject = SingletonFactory.getInstance(Subject);
		var id = this.getRequest().getParam('id');
		if (id == undefined || isNaN(id))	{
			subject.notifyEvent('RequestRoute', new Request('ErrorPage', undefined, {'code':404}));
			return;
		}
		var obj = this;
		obj.model = {};
		obj.model.id = id;
		obj.getPortletPlaceholder().paintCanvas(obj.render());
		this.onAjax('catchword', 'get-topic-details', {'id':id}, 'GET', {
			'onSuccess': function(ret)	{
				obj.requestForEffectiveResource('TopicName').html(ret.catchWord);
				obj.requestForEffectiveResource('TopicDetail').html(ret.detail);
				if (ret.avatar == undefined || ret.avatar == '')	{
					ret.avatar = 'asking.png';
				}
				obj.requestForEffectiveResource('TopicAvatar').attr('src', 'resource/images/topics/'+ret.avatar);
			},
			
			'onFailure': function(message)	{
				subject.notifyEvent('RequestRoute', new Request('ErrorPage', undefined, {'code':404}));
			}
		});
		
		this.onAjax('catchword', 'get-topic-stats', {'id':id}, 'GET', {
			'onSuccess': function(ret)	{
				obj.requestForEffectiveResource('ExpertCount').html(ret.expert);
				obj.requestForEffectiveResource('FollowCount').html(ret.follow);
				obj.requestForEffectiveResource('AnswerCount').html(ret.answer);
				obj.requestForEffectiveResource('QuestionCount').html(ret.question);
			}
		}, true, 300000);
	}
}).implement(PortletInterface).implement(RenderInterface).implement(AjaxInterface);
AbstractFollowersPortlet = Class.extend({
	init: function()	{
	},
	
	onBegin: function()	{
		this.registerObserver();
	},
	
	onReloadPage: function()	{
		this.fetchFollowerList();
	},
	
	run: function()	{
		this.fetchFollowerList();
	},
	
	fetchFollowerList: function(){
		var uid = this.getRequest().getParam(this.key);
		var obj = this;
		
		this.onAjax(this.controller, this.action, {'uid': uid}, 'GET', {
			'onSuccess': function(ret)	{
				obj.model = {};
				obj.model.list = ret;
				if (uid == undefined)
					obj.model.pronoun = "bạn";
				else
					obj.model.pronoun = "người này";
				obj.getPortletPlaceholder().paintCanvas(obj.render());
			}
		});
	},
	
	onEnd: function()	{
		this.unregisterObserver();
	}
}).implement(PortletInterface).implement(RenderInterface).implement(AjaxInterface).implement(ObserverInterface);
AllUsersPortlet = Class.extend({
	init: function()	{
		this.name = "AllUsersPortlet";
	},
	
	run: function(name)	{
		var obj = this;
		this.onAjax('ajax', 'get-all-users', {}, 'GET', {
			'onSuccess': function(ret)	{
				var maxLength = 20;
				for(var i in ret)	{
					if (ret[i].catchWord.length > maxLength)	{
						var trimmed = ret[i].catchWord.substr(0, maxLength - 3);
						var lastWordIndex = trimmed.lastIndexOf(' ');
						if (lastWordIndex != -1)	{
							trimmed = trimmed.substr(0, lastWordIndex);
						}
						ret[i].catchWord = trimmed+"...";
					}
				}
				
				ret.sort(function(a, b) {
					return b.catchWord.length - a.catchWord.length;
				});
				
				obj.model = {};
				obj.model.catchwords = ret;

				obj.getPortletPlaceholder().paintCanvas(obj.render());
				obj.requestForEffectiveResource('ContentPlaceholder').find('ul:first').addClass('first');
				obj.requestForEffectiveResource('ContentPlaceholder').find('ul:last').addClass('last');
			}
		}, true, 300000);
	}
}).implement(PortletInterface).implement(RenderInterface).implement(AjaxInterface).implement(ObserverInterface);
BriefInfoEditPortlet = Class.extend({
	init: function()	{
		this.name = "BriefInfoEditPortlet";
	},
	
	run: function()	{
		this.model = {};
		var obj = this;
		var props = SingletonFactory.getInstance(Application).getSystemProperties();
		this.onAjax('user-ajax', 'get-brief-info', {}, 'GET', {
			'onSuccess': function(ret)	{
				obj.model.page = obj.getRequest().getParam('page');
				obj.model.id = props.get('user.id');
				obj.model.name = ret.name;
				obj.model.avatar = ret.avatar;
				obj.getPortletPlaceholder().paintCanvas(obj.render());
			}
		});
	}
}).implement(PortletInterface).implement(AjaxInterface).implement(RenderInterface);
ContactsPortlet = Class.extend({
	init: function()	{
		this.name = "ContactsPortlet";
		this.page = 0;
	},
	
	onBegin: function()	{
		this.registerObserver();
	},
	
	run: function()	{
		this.fetchContacts();
	},
	
	onShowMoreMyContacts: function() {
		var obj = this;
		this.page++;
		this.onAjax('user-ajax', 'get-contacts', {page: this.page}, 'GET', {
			'onSuccess': function(ret)	{
				if (ret.length > 0)	{
					obj.requestForEffectiveResource('Container').append(obj.renderView('Contacts', {contacts: ret}));
				}
				if (ret.length < 20)	{
					obj.requestForEffectiveResource('ShowMore').hide();
				}
			}
		});
	},
	
	fetchContacts: function(){
		var obj = this;
		this.onAjax('user-ajax', 'get-contacts', {page: this.page}, 'GET', {
			'onSuccess': function(ret)	{
				obj.model = {};
				obj.model.contacts = ret;
				obj.getPortletPlaceholder().paintCanvas(obj.render());
				if (ret.length > 0)	{
					obj.requestForEffectiveResource('Container').html(obj.renderView('Contacts', {contacts: ret}));
				}
				if (ret.length < 20)	{
					obj.requestForEffectiveResource('ShowMore').hide();
				}
			}
		});
	},
	
	onSendInviteButtonClick: function(eventData)	{
		var email = eventData.email;
		var origin = eventData.origin.target;
		var plhd = $(origin).parent();
		plhd.html('<img class="invite-ajax-loader" src="resource/images/ajax-loader-1.gif">');
		this.onAjax('invitation', 'send-invitation', {'email': email}, 'POST', {
			'onSuccess': function()	{
				$(plhd).html('<strong class="InvitationSent">Đã gửi lời mời</strong>');
			},
			
			'onFailure': function()	{
				$(plhd).html('<div class="errorMsg">Gửi thất bại!</div>');
			}
		});
	},
	
	onEnd: function()	{
		this.unregisterObserver();
	}
}).implement(PortletInterface).implement(RenderInterface).implement(AjaxInterface).implement(ObserverInterface);
EmailPasswdEditPortlet = Class.extend({
	init: function()	{
		this.name = "EmailPasswdEditPortlet";
	},
	
	onBegin: function()	{
		this.registerObserver();
	},
	
	afterEdit: function(target) {
		$('.'+target).show();
		$('.'+target+'_edit').hide();
		$('.error').html('');
	},
	
	onSubmitNewsletter: function() {
		$('.error').html('');
		var checkbox = this.requestForEffectiveResource('NewsletterCheck');
		var email = this.requestForEffectiveResource('NewsletterEmail').val().trim();
		
		var obj = this;
		var subject = SingletonFactory.getInstance(Subject);
		if (checkbox.is(':checked'))	{
			if (email == "")	{
				this.requestForEffectiveResource('EmailError').html("Email không được để trống");
				return;
			}
			
			this.onAjax('ajax', 'subscribe', {email: email}, 'POST', {
				'onSuccess': function(ret)	{
					subject.notifyEvent('NotifyGlobal', 'Bạn đã đăng ký nhận newsletter thành công!');
					obj.run();
				},
				'onFailure': function(message)	{
					obj.requestForEffectiveResource('EmailNewsletterError').html(message);
				}
			});
		} else {
			this.onAjax('ajax', 'unsubscribe-user', {}, 'POST', {
				'onSuccess': function(ret)	{
					subject.notifyEvent('NotifyGlobal', 'Bạn đã hủy nhận newsletter thành công!');
					obj.run();
				}
			});
		}
	},
	
	onSubmitEmail: function() {
		$('.error').html('');
		var curPass = this.requestForEffectiveResource('EmailPass').val().trim();
		var email = this.requestForEffectiveResource('EmailInput').val().trim();
		
		var obj = this;
		if (curPass == "")	{
			obj.requestForEffectiveResource('EmailPassError').html("Bạn phải nhập mật khẩu hiện tại");
			return;
		}
		if (email == "")	{
			obj.requestForEffectiveResource('EmailError').html("Email không được để trống");
			return;
		}
		
		this.onAjax('user-ajax', 'edit-email-password', {currentPasswd: curPass, email: email}, 'POST', {
			'onSuccess': function(ret)	{
				var subject = SingletonFactory.getInstance(Subject);
				subject.notifyEvent('NotifyGlobal', 'Bạn đã thay đổi email thành công!');
				obj.afterEdit('bkp_email');
				obj.requestForEffectiveResource('EmailPass').val('');
				obj.requestForEffectiveResource('Email').html(email);
			},
			'onFailure': function(message)	{
				if (message.indexOf('sai') == -1)
					obj.requestForEffectiveResource('EmailError').html(message);
				else
					obj.requestForEffectiveResource('EmailPassError').html(message);
			}
		});
	},
	
	onSubmitPasswd: function()	{
		$('.error').html('');
		var curPass = this.requestForEffectiveResource('CurrentPasswd').val().trim();
		var pass = this.requestForEffectiveResource('Passwd').val().trim();
		var confirmPass = this.requestForEffectiveResource('ConfirmPasswd').val().trim();

		var obj = this;
		if (curPass == "")	{
			obj.requestForEffectiveResource('CurPassError').html("Bạn phải nhập mật khẩu cũ");
			return;
		}
		if (pass == "")	{
			obj.requestForEffectiveResource('NewPassError').html("Mật khẩu không được để trống");
			return;
		}
		if (pass != confirmPass)	{
			obj.requestForEffectiveResource('ConfirmPassError').html("Hai mật khẩu phải giống nhau");
			return;
		}
		
		this.onAjax('user-ajax', 'edit-email-password', {'currentPasswd': curPass, 'passwd': pass}, 'POST', {
			'onSuccess': function(ret)	{
				var subject = SingletonFactory.getInstance(Subject);
				subject.notifyEvent('NotifyGlobal', 'Bạn đã thay đổi mật khẩu thành công!');
				obj.afterEdit('bkp_passwd');
				obj.requestForEffectiveResource('CurrentPasswd').val('');
				obj.requestForEffectiveResource('Passwd').val('');
				obj.requestForEffectiveResource('ConfirmPasswd').val('');
			},
			'onFailure': function(message)	{
				if (message.indexOf('sai') == -1)
					obj.requestForEffectiveResource('NewPassError').html(message);
				else
					obj.requestForEffectiveResource('CurPassError').html(message);
			}
		});
	},
	
	onNewsletterSubscribeCheckChanged: function() {
		var input = this.requestForEffectiveResource('NewsletterCheck');
		if (input.is(':checked'))	{
			this.requestForEffectiveResource('NewsletterEmail').removeAttr('disabled');
		} else {
			this.requestForEffectiveResource('NewsletterEmail').attr('disabled', '');
		}
	},
	
	run: function()	{
		var obj = this;
		var prop = SingletonFactory.getInstance(Application).getSystemProperties();
		obj.model = {};
		obj.model.name = prop.get('user.name');
		obj.model.username = prop.get('user.username');
		obj.model.avatar = prop.get('user.avatar');
		obj.model.newsletter = "Tắt";
		obj.model.newsletterChecked = "";
		obj.model.newsletterDisable = "disabled";
		obj.model.newsletterEmail = "";
		this.onAjax('user-ajax', 'get-user-edit-info', {}, 'GET', {
			'onSuccess': function(ret)	{
				if (ret.subscribe != null)	{
					obj.model.newsletter = "Bật";
					obj.model.newsletterChecked = "checked";
					obj.model.newsletterDisable = "";
					obj.model.newsletterEmail = ret.subscribe.email;
				}
				
				obj.getPortletPlaceholder().paintCanvas(obj.render());
				obj.requestForEffectiveResource('Email').html(ret.email);
				obj.requestForEffectiveResource('EmailInput').val(ret.email);
			}
		});
	},
	
	onEnd: function()	{
		this.unregisterObserver();
	}
}).implement(PortletInterface).implement(RenderInterface).implement(AjaxInterface).implement(ObserverInterface);
EmailRecoverPortlet = Class.extend({
	init: function()	{
		this.name = "EmailRecoverPortlet";
	},
	
	onBegin: function()	{
		this.registerObserver();
	},
	
	onRecoverButtonClick: function()	{
		var obj = this;
		var email = this.requestForEffectiveResource('Email').val();
		this.requestForEffectiveResource('Email').attr('disabled', 'true');
		this.requestForEffectiveResource('Error').html('<img src="resource/images/ajax-loader-1.gif">');
		
		this.onAjax('user-ajax', 'request-new-password', 
				{'email': email}, 'POST', {
						'onSuccess': function()	{
							var subject = SingletonFactory.getInstance(Subject);
							subject.notifyEvent('NotifyGlobal', 'Chúng tôi đã gửi hướng dẫn phục hồi mật khẩu đến email của bạn! Hướng dẫn có giá trị trong vòng 24h');
							subject.notifyEvent('RequestRoute', new Request('Home'));
						},
						
						'onFailure': function(message)	{
							obj.requestForEffectiveResource('Email').removeAttr('disabled');
							obj.requestForEffectiveResource('Error').html(message);
						}
					});
	},
		
	run: function()	{
		this.getPortletPlaceholder().paintCanvas(this.render());
	},
	
	onEnd: function()	{
		this.unregisterObserver();
	}
}).implement(PortletInterface).implement(RenderInterface).implement(AjaxInterface).implement(ObserverInterface);
/**
 * @author KhanhHH
 */
ListFollowersPortlet = AbstractFollowersPortlet.extend({
	init: function()	{
		this.name = "ListFollowersPortlet";
		this.key = 'id';
		this.controller = 'user-ajax';
		this.action = 'get-followers';
	},
	
	onFollowersChange: function()	{
		this.run();
	},
	
	onListAllFollowers: function() {
		var subject = SingletonFactory.getInstance(Subject);
		subject.notifyEvent('ShowPopup', {id: 'ListFollowers', title: 'Những người đang follow', content: this.renderView('AllPeople', this.model)});
	}
}).implement(PortletInterface).implement(RenderInterface).implement(AjaxInterface).implement(ObserverInterface);
ListFollowingPortlet = ListFollowersPortlet.extend({
	init: function()	{
		this._super();
		this.name = "ListFollowingPortlet";
		this.action = "get-following";
	},
	
	onListAllFollowing: function() {
		var subject = SingletonFactory.getInstance(Subject);
		subject.notifyEvent('ShowPopup', {id: 'ListFollowers', title: 'Những người đang follow', content: this.renderView('AllPeople', this.model)});
	}
}).implement(PortletInterface).implement(RenderInterface).implement(AjaxInterface).implement(ObserverInterface);
LoginPortlet = Class.extend({
	
	init: function()	{
		this.name = "LoginPortlet";
		this.model = {};
	},
	
	onBegin: function()	{
		this.registerObserver();
	},
	
	onOpenIDLoginSuccess: function() {
		var subject = SingletonFactory.getInstance(Subject);
		subject.notifyEvent('PopupRemove', {id: 'Login'});
		this.resyncStatus();
	},
	
	onLoginOpenID: function(eventData) {
		var w = 800;
		var h = 450;
		var left = (screen.width/2)-(w/2);
		var top = (screen.height/2)-(h/2);
		window.open('index/login-openid/login/'+eventData.type, 'openIDWindow', "status = 0, height = "+h+", width = "+h+", resizable = 0, left = "+left+", top = "+top);
	},
	
	onNeedLogin: function(eventData)	{
		this.currentEventData = eventData;
		//check login?
		var properties = SingletonFactory.getInstance(Application).getSystemProperties();
		var loggedIn = properties.get('user.login', undefined);
		//no evidence found
		if (loggedIn == undefined)	{
			this.resyncStatus(eventData);
		} else {
			this.checkLogin(eventData);
		}
	},
	
	resyncStatus: function(eventData)	{
		var obj = this;
		var properties = SingletonFactory.getInstance(Application).getSystemProperties();
		this.onAjax('ajax', 'check-user-status', {}, 'GET', 
			{'onSuccess': function(ret)	{
				if (ret == 0)	{
					properties.set('user.login', 0, true);
					properties.set('user.id', -1, true);
				} else {
					properties.set('user.id', ret.id, true);
					properties.set('user.name', ret.name, true);
					properties.set('user.login', 1, true);
					properties.set('user.type', ret.type, true);
					properties.set('user.role', ret.role, true);
				}
				obj.checkLogin(eventData);
			}
		});
	},
	
	checkLogin: function(eventData)	{
		var subject = SingletonFactory.getInstance(Subject);
		var properties = SingletonFactory.getInstance(Application).getSystemProperties();
		var loggedIn = properties.get('user.login', undefined);
		if (loggedIn == 0)	{
			if (this.currentEventData.disableWarning == true)
				this.model.loginError = '';
			else 
				this.model.loginError = this.getLocalizedText('NeedLogin');
			subject.notifyEvent('ShowPopup', {'id': 'Login',title: 'Đăng nhập', 'content': this.render()});
			$('#LoginPortlet-Username').focus();
		} else {
			subject.notifyEvent('LoginSuccess', eventData);
		}
	},
	
	onPasswordTextBoxKeyUp: function(event)	{
		var keycode = event.keyCode;
		if (keycode == 13)	{
			this.onLoginButtonClick(event);
		}
	},
	
	onLoginButtonClick: function(eventData)	{
		var target = eventData.target;
		var form = $(target).parents('#LoginPortlet-Form:first');
		//ajax request
		var username = $(form).find('#LoginPortlet-Username').val();
		var password = $(form).find('#LoginPortlet-Password').val();
		var remember = $(form).find('#LoginPortlet-Persistent:checked').length;
		var loginError = $(target).parents('#LoginPortlet-Form:first').find('#LoginPortlet-LoginError');
		if (username == '' || password == '')	{
			$(loginError).html(this.getLocalizedText('LoginInsufficientInput'));
		}
		var obj = this;
		this.onAjax('ajax', 'login', {'username':username, 'password':password, 'persistent': remember}, 'POST', 
				{'onSuccess': function(ret)	{
					var properties = SingletonFactory.getInstance(Application).getSystemProperties();
					properties.set('user.id', ret.id, true);
					properties.set('user.name', ret.name, true);
					properties.set('user.login', 1, true);
					properties.set('user.type', ret.type, true);
					var subject = SingletonFactory.getInstance(Subject);
					subject.notifyEvent('PopupRemove', {id: 'Login'});
					subject.notifyEvent('LoginSuccess', obj.currentEventData);
				},
				'onFailure': function(message)	{
					$(loginError).html(message);
				}});
	},
	
	onReloadPage: function() {
		this.run();
	},
	
	onSystemPropertyChanged: function(eventData)	{
		if (eventData == 'user.login')	{
			if (this.getInitParameters().light == true) {
				var loggedin = SingletonFactory.getInstance(Application).getSystemProperties().get('user.login');
				if (loggedin == 1)
					this.getPortletPlaceholder().paintCanvas('');
			}
		}
	},
	
	run: function()	{
		this.model.loginError = '';
		if (this.getInitParameters().light == true) {
			var loggedin = SingletonFactory.getInstance(Application).getSystemProperties().get('user.login');
			if (loggedin != 1)
				this.getPortletPlaceholder().paintCanvas(this.renderView('LightView', this.model));
		} else {
			this.getPortletPlaceholder().paintCanvas(this.render());
		}
	}
}).implement(RenderInterface).implement(PortletInterface).implement(ObserverInterface).implement(AjaxInterface);

NotificationListPortlet = Class.extend({
	init: function()	{
		this.name = "NotificationListPortlet";
		this.page = 0;
	},
	
	onViewMoreNotification: function()	{
		this.page++;
		this.fetch();
	},
	
	run: function()	{
		this.getPortletPlaceholder().paintCanvas(this.render());
		this.fetch();
	},
	
	fetch: function() {
		var obj = this;
		this.onAjax('user-ajax', 'get-all-notification', {page: this.page}, 'GET', {
			'onSuccess': function(ret)	{
				if (ret.length < 20)
					obj.requestForEffectiveResource('ViewMore').hide();
				if (ret.length == 0)	{
					if (obj.page == 0)
						obj.requestForEffectiveResource('Container').html('Hiện tại bạn không có thông báo nào');
				} else {
					var notifs = Array();
					for(var i=0;i<ret.length;i++)	{
						var link = eval("("+ret[i].link+")");
						var href=Array();
						for(var j in link)	{
							var param = j;
							if (param == 'type')
								param = 'page';
							else if (param == 'qid')
								ret[i].objId = link[j];
							href.push(param+"/"+link[j]);
						}
						ret[i].link = "#!"+href.join("/");
						ret[i].users = Array();
						ret[i].users.push({sourceId: ret[i].sourceId, name: ret[i].name});
						var since = $.timeFormatMin(ret[i].since);
						if (notifs[since] == undefined)
							notifs[since] = Array();
						var found = false;
						for(var j in notifs[since])	{
							if (ret[i].type == notifs[since][j].type && ret[i].objId == notifs[since][j].objId)	{
								notifs[since][j].users.push({sourceId: ret[i].sourceId, name: ret[i].name});
								found = true;
								break;
							}
						}
						if (!found)
							notifs[since].push(ret[i]);
					}
					for(var i in notifs)	{
						for(var j in notifs[i]) {
							notifs[i][j].usersTmpl = obj.renderView('UsersTemplate', {users: notifs[i][j].users});
							notifs[i][j].content = obj.renderView(notifs[i][j].type, notifs[i][j]);
						}
					}
					obj.requestForEffectiveResource('Container').append(obj.renderView('List', {notifs: notifs}));
				}
			}
		});
	},
	
	onBegin: function() {
		this.registerObserver();
	},
	
	onEnd: function() {
		this.unregisterObserver();
	}
}).implement(PortletInterface).implement(RenderInterface).implement(AjaxInterface).implement(ObserverInterface);
PasswordResetPortlet = Class.extend({
	init: function()	{
		this.name = "PasswordResetPortlet";
	},
	
	onBegin: function()	{
		this.registerObserver();
	},
	
	onReloadPage: function()	{
		this.run();
	},
	
	onResetButtonClick: function()	{
		var obj = this;
		var pw = this.requestForEffectiveResource('Password').val();
		var cfpw = this.requestForEffectiveResource('ConfirmPassword').val();
		if (pw == undefined || pw == "")	{
			obj.requestForEffectiveResource('Error').html('Bạn phải nhập mật khẩu');
			return;
		}
		if (pw != cfpw)	{
			obj.requestForEffectiveResource('Error').html('Hai mật khẩu không giống nhau');
			return;
		}
		
		var token = this.token;
		if (token == undefined)	{
			token = this.getRequest().getParam('token');
		}
		
		this.onAjax('user-ajax', 'reset-password', 
				{'token': token, 'passwd': pw}, 'POST', {
						'onSuccess': function()	{
							var subject = SingletonFactory.getInstance(Subject);
							subject.notifyEvent('NotifyGlobal', 'Bạn đã thay đổi mật khẩu thành công');
							subject.notifyEvent('RequestRoute', new Request('Login'));
						},
						
						'onFailure': function(message)	{
							obj.requestForEffectiveResource('Error').html(message);	
						}
					});
	},
		
	run: function()	{
		this.getPortletPlaceholder().paintCanvas('');
		var token = this.getRequest().getParam('token', undefined);
		if (token == undefined)	{
			this.getPortletPlaceholder().paintCanvas(this.renderView('ErrorInvalidToken', {}));
		} else {
			var obj = this;
			this.onAjax('user-ajax', 'is-token-valid', {'token':token}, 'GET', {
				'onSuccess': function(ret)	{
					obj.token = token;
					obj.getPortletPlaceholder().paintCanvas(obj.render());
				},
				'onFailure': function(message)	{
					obj.getPortletPlaceholder().paintCanvas(obj.renderView('ErrorInvalidToken', {error: message}));
				}
			});
		}
	},
	
	onEnd: function()	{
		this.unregisterObserver();
	}
}).implement(PortletInterface).implement(RenderInterface).implement(AjaxInterface).implement(ObserverInterface);
PrivilegePortlet = Class.extend({
	init: function()	{
		this.name = "PrivilegePortlet";
	},
	
	onBegin: function()	{
		this.registerObserver();
	},
	
	run: function()	{
		var obj = this;
		this.getPortletPlaceholder().paintCanvas(this.render());
		this.onAjax('ajax', 'get-all-privileges', {}, 'GET', {
			'onSuccess': function(ret) {
				var privs = Array();
				for(var i in ret.privs)	{
					privs.push({title: ret.privs[i].title, requiredScore: ret.privs[i].requiredScore});
				}
				ret.privs = privs;
				ret.privs.sort(function(a, b) {
					return b.requiredScore - a.requiredScore;
				});
				var remainingScore = 0;
				for(var i=1;i<ret.privs.length;i++)	{
					if (parseInt(ret.privs[i].requiredScore) <= parseInt(ret.current))	{
						remainingScore = ret.privs[i-1].requiredScore - ret.current;
						if (remainingScore < 0)
							remainingScore = 0;
						break;
					}
				}
				ret.remainingScore = remainingScore;
				obj.requestForEffectiveResource('ContentPlaceholder').html(obj.renderView('Privileges', ret));
			}
		});
	},
	
	onEnd: function()	{
		this.unregisterObserver();
	}
}).implement(PortletInterface).implement(RenderInterface).implement(ObserverInterface).implement(AjaxInterface);
QuestionFollowersPortlet = ListFollowersPortlet.extend({
	init: function()	{
		this.name = "QuestionFollowersPortlet";
		this.key = "qid";
		this.controller = "question";
		this.action = "get-followers";
	},
	
	onQuestionFollowerChange: function()	{
		this.run();
	}
}).implement(PortletInterface).implement(RenderInterface).implement(AjaxInterface).implement(ObserverInterface);

RegisterPortlet = Class.extend({
	init: function()	{
		this.name = "RegisterPortlet";
		this.step = 1;
		this.subject = SingletonFactory.getInstance(Subject);
	},
	
	onBegin: function()	{
		this.model = {};
		this.model.welcomeMsg = this.getLocalizedText('Welcome');
		this.model.nameMsg = this.getLocalizedText('Name');
		this.model.usernameMsg = this.getLocalizedText('Username');
		this.model.passwordMsg = this.getLocalizedText('Password');
		this.model.emailMsg = this.getLocalizedText('Email');
		this.model.submitMsg = this.getLocalizedText('Submit');
		this.model.skipMsg = this.getLocalizedText('Skip');
		this.model.registerMsg = this.getLocalizedText('Register');
		this.model.additionInfoMsg = this.getLocalizedText('AdditionInfo');
		this.model.expertiseMsg = this.getLocalizedText('Expertise');
		this.model.tokenMsg = this.getLocalizedText('Token');
		
		this.model.passwordTitle = this.getLocalizedText('PasswordTitle');
		this.model.emailTitle = this.getLocalizedText('EmailTitle');
		this.registerObserver();
	},
	
	run: function()	{
		this.model.existEmail = "";
		this.model.preEmail = this.getRequest().getParam('email') || "";
		this.model.preName = this.getRequest().getParam('name') || "";
		this.step1();
	},
	
	step1: function()	{
		this.getPortletPlaceholder().drawToCanvas(this.renderView('ViewStep1', this.model));
	},
	
	step1ClearError: function()	{
		this.requestForEffectiveResource('NameError').html('');
		this.requestForEffectiveResource('PasswordError').html('');
		this.requestForEffectiveResource('EmailError').html('');
		this.requestForEffectiveResource('TokenError').html('');
	},
	
	onRegisterButtonClick: function(eventData)	{
		var fullname = this.requestForEffectiveResource('Name').val();
		var password = this.requestForEffectiveResource('Password').val();
		var email = this.requestForEffectiveResource('Email').val();
		var token = this.requestForEffectiveResource('Token').val();
		var receive = this.requestForEffectiveResource('ReceiveUpdates').is(':checked') ? 1 : 0;
		var refererToken = this.getRequest().getParam('token');
		
		var subject = SingletonFactory.getInstance(Subject);
		
		var obj = this;
		this.step1ClearError();
		this.onAjax('ajax', 'register', 
				{'password':password, 'email':email, 'fullname':fullname
					, 'token': token, 'refererToken': refererToken, receive: receive}
				, 'POST', 
				{onSuccess: function(ret)	{
					subject.notifyEvent('UpdateUserStatus');
					if (obj.getInitParameters().type == 'home')
						obj.end();
					else
						obj.step3();
				},
				onFailure: function(msg, data)	{
					for(var i in data)	{
						var err = data[i];
						obj.handleRegisterError(err.type, err.msg);
					}
				}});
	},
	
	handleRegisterError: function(errType, errMsg)	{
		switch(errType)	{
		case "fullname":
			this.requestForEffectiveResource('NameError').html(errMsg);
			break;
		case "password":
			this.requestForEffectiveResource('PasswordError').html(errMsg);
			break;
		case "email":
			this.requestForEffectiveResource('EmailError').html(errMsg);
			break;
		case "token":
			this.requestForEffectiveResource('TokenError').html(errMsg);
			break;
		}
	},
	
	onLoginSuccess: function(eventData)	{
		if (eventData.type == 'Register')	{
			this.end();
		}
	},
	
	step3: function()	{
		this.getPortletPlaceholder().paintCanvas(this.renderView('ViewStep3', this.model));
		var subject = SingletonFactory.getInstance(Subject);
		subject.notifyEvent('RenderExpertiseEditor', {placeholder:this.requestForEffectiveResource('ExpertisePlaceholder'), namespace:'RegisterPortlet'});
		subject.notifyEvent('RenderInterestEditor', {placeholder:this.requestForEffectiveResource('InterestPlaceholder'), namespace:'RegisterPortlet'});
	},
	
	onSkipExpertiseRegisterButtonClick: function(eventData)	{
		this.end();
	},
	
	onSubmitExpertiseRegisterButtonClick: function(eventData)	{
		var subject = SingletonFactory.getInstance(Subject);
		var obj = this;
		this.submitComplete = 0;
		subject.notifyEvent('SubmitExpertiseForward', {callback: function()	{
			obj.expertiseSubmitted();
		}, namespace: this.name});
		subject.notifyEvent('SubmitInterestForward', {callback: function()	{
			obj.expertiseSubmitted();
		}, namespace: this.name});
	},
	
	expertiseSubmitted: function()	{
		this.submitComplete++;
		if (this.submitComplete >= 2)	{
			this.end();
		}
	},
	
	onEnd: function()	{
		this.unregisterObserver();
	},
	
	end: function()	{
		var request = new Request("UserAvatarEdit", null, {msg: 'reg_complete'});
		var subject = SingletonFactory.getInstance(Subject);
		subject.notifyEvent('RequestRoute', request);
	}
}).implement(PortletInterface).implement(RenderInterface).implement(ObserverInterface).implement(AjaxInterface);
UserBrowserPortlet = Class.extend({
	init: function()	{
		this.name = "UserBrowserPortlet";
	},
	
	run: function()	{
		var obj = this;
		this.getPortletPlaceholder().paintCanvas(this.render());
		this.onAjax('ajax', 'get-max-score-users', {}, 'GET', {
			'onSuccess': function(ret)	{
				obj.requestForEffectiveResource('ContentPlaceholder-MaxScore').html(obj.renderView('MaxScoreList', {users: ret}));
			}
		}, true, 300000);
		
		this.onAjax('ajax', 'get-by-top-rank', {}, 'GET', {
			'onSuccess': function(ret)	{
				obj.model = {};
				obj.model.users = Array();
				var map = Array();
				for (var i in ret)	{
					if (ret[i] == undefined)
						continue;
					var id = ret[i].userId;
					if (map[id] == undefined)	{
						map[id] = i;
						ret[i].ranks = "<a class='lv_tag' href='#!page/Topic/id/"+ret[i].expertiseId+"'>"+ret[i].catchWord+"</a>";
					} else {
						var index = map[id];
						ret[index].ranks += ', '+"<a class='lv_tag' href='#!page/Topic/id/"+ret[i].expertiseId+"'>"+ret[i].catchWord+"</a>";
						ret[i] = undefined;
					}
				}
				
				for(var i in ret)	{
					if (ret[i] != undefined)
						obj.model.users.push(ret[i]);
				}

				obj.requestForEffectiveResource('ContentPlaceholder-TopRank').append(obj.renderView('TopRankList', obj.model));
			}
		}, true, 300000);
		
		this.onAjax('ajax', 'get-latest-users', {}, 'GET', {
			'onSuccess': function(ret)	{
				obj.requestForEffectiveResource('ContentPlaceholder-Latest').html(obj.renderView('LatestList', {users: ret}));
			}
		}, true, 300000);
	}
}).implement(PortletInterface).implement(RenderInterface).implement(AjaxInterface);
FollowRecommendPortlet = Class.extend({
	init: function()	{
		this.name = "FollowRecommendPortlet";
	},
	
	onBegin: function()	{
		this.registerObserver();
	},
	
	onEnd: function()	{
		this.unregisterObserver();
	},
	
	onFollowPerson: function(eventData) {
		var obj = this;
		this.onAjax('user-ajax', 'follow-user', {'uid': eventData.id}, 'POST', {
			'onSuccess': function(ret)	{
				obj.run();
			}
		});
	},
	
	run: function()	{
		var obj = this;
		this.onAjax('user-ajax', 'get-follow-recommend', {}, 'get', {
			onSuccess: function(ret) {
				obj.model = {list: ret};
				obj.getPortletPlaceholder().paintCanvas(obj.render());
			}
		});
	}
}).implement(PortletInterface).implement(RenderInterface).implement(AjaxInterface).implement(ObserverInterface);
//Fix bug in IE
if (typeof String.prototype.trim !== 'function') {   
	String.prototype.trim = function() {
		return this.replace(/^\s+|\s+$/g, "");   
	} 
}
if(typeof Array.prototype.indexOf !== 'function'){
	Array.prototype.indexOf = function(obj){
		for(var i=0; i<this.length; i++){
    		if(this[i]==obj){
        		return i;
    		}
		}
		return -1;
	}
}
var bkbootstrap = new BKBootstrap();
var app = SingletonFactory.getInstance(Application);
app.getSystemProperties().set("host.root", ApplicationRoot);
app.getSystemProperties().set("host.solr", "/solr");
app.getSystemProperties().set("page.default", "Home");
app.setBootstrap(bkbootstrap);
Request.setProactive(true);

$(window).bind("hashchange", function(){
    if (Request.getProactive != true) {
        var subject = SingletonFactory.getInstance(Subject);
        subject.notifyEvent('NeedAssembleRequest');
    }
    Request.setProactive(false);
});

$(document).ready(function()	{
	$.get(ApplicationRoot+'/resource/microtemplating/all.fall.txt', {}, function(ret)	{
		var useragent = navigator.userAgent;
		if (useragent.indexOf('MSIE') != -1)	{
			$('#Application-Main').html(ret);
		} else {
			document.getElementById('Application-Main').innerHTML = ret;
		}
		app.begin();
	});
});

(function(){var g=void 0,h=!0,i=null,k=!1,aa=encodeURIComponent,ba=Infinity,ea=setTimeout,fa=decodeURIComponent,l=Math;function ga(a,b){return a.name=b}
var m="push",ha="slice",n="replace",ia="load",ja="floor",ka="charAt",la="value",p="indexOf",ma="match",na="port",oa="createElement",pa="path",q="name",t="host",u="toString",v="length",w="prototype",qa="clientWidth",x="split",ra="stopPropagation",ta="scope",y="location",ua="search",z="protocol",va="clientHeight",wa="href",A="substring",xa="apply",ya="navigator",B="join",C="toLowerCase",D;function za(a,b){switch(b){case 0:return""+a;case 1:return 1*a;case 2:return!!a;case 3:return 1E3*a}return a}function Aa(a){return"function"==typeof a}function Ba(a){return a!=g&&-1<(a.constructor+"")[p]("String")}function E(a,b){return g==a||"-"==a&&!b||""==a}function Ca(a){if(!a||""==a)return"";for(;a&&-1<" \n\r\t"[p](a[ka](0));)a=a[A](1);for(;a&&-1<" \n\r\t"[p](a[ka](a[v]-1));)a=a[A](0,a[v]-1);return a}
function F(a){var b=1,c=0,d;if(!E(a)){b=0;for(d=a[v]-1;0<=d;d--)c=a.charCodeAt(d),b=(b<<6&268435455)+c+(c<<14),c=b&266338304,b=0!=c?b^c>>21:b}return b}function Da(){return l.round(2147483647*l.random())}function Ea(){}function G(a,b){if(aa instanceof Function)return b?encodeURI(a):aa(a);H(68);return escape(a)}function I(a){a=a[x]("+")[B](" ");if(fa instanceof Function)try{return fa(a)}catch(b){H(17)}else H(68);return unescape(a)}
var Fa=function(a,b,c,d){a.addEventListener?a.addEventListener(b,c,!!d):a.attachEvent&&a.attachEvent("on"+b,c)},Ga=function(a,b,c,d){a.removeEventListener?a.removeEventListener(b,c,!!d):a.detachEvent&&a.detachEvent("on"+b,c)};function Ha(a,b){if(a){var c=J[oa]("script");c.type="text/javascript";c.async=h;c.src=a;c.id=b;var d=J.getElementsByTagName("script")[0];d.parentNode.insertBefore(c,d);return c}}function K(a){return a&&0<a[v]?a[0]:""}function Ia(a){var b=a?a[v]:0;return 0<b?a[b-1]:""}
var Ja=function(){this.prefix="ga.";this.R={}};Ja[w].set=function(a,b){this.R[this.prefix+a]=b};Ja[w].get=function(a){return this.R[this.prefix+a]};Ja[w].contains=function(a){return this.get(a)!==g};function Ka(a){0==a[p]("www.")&&(a=a[A](4));return a[C]()}function La(a,b){var c,d={url:a,protocol:"http",host:"",path:"",d:new Ja,anchor:""};if(!a)return d;c=a[p]("://");0<=c&&(d.protocol=a[A](0,c),a=a[A](c+3));c=a[ua]("/|\\?|#");if(0<=c)d.host=a[A](0,c)[C](),a=a[A](c);else return d.host=a[C](),d;c=a[p]("#");0<=c&&(d.anchor=a[A](c+1),a=a[A](0,c));c=a[p]("?");0<=c&&(Ma(d.d,a[A](c+1)),a=a[A](0,c));d.anchor&&b&&Ma(d.d,d.anchor);a&&"/"==a[ka](0)&&(a=a[A](1));d.path=a;return d}
function Na(a,b){function c(a){var b=(a.hostname||"")[x](":")[0][C](),c=(a[z]||"")[C](),c=1*a[na]||("http:"==c?80:"https:"==c?443:""),a=a.pathname||"";0==a[p]("/")||(a="/"+a);return[b,""+c,a]}var d=b||J[oa]("a");d.href=J[y][wa];var e=(d[z]||"")[C](),f=c(d),j=d[ua]||"",o=e+"//"+f[0]+(f[1]?":"+f[1]:"");0==a[p]("//")?a=e+a:0==a[p]("/")?a=o+a:!a||0==a[p]("?")?a=o+f[2]+(a||j):0>a[x]("/")[0][p](":")&&(a=o+f[2][A](0,f[2].lastIndexOf("/"))+"/"+a);d.href=a;e=c(d);return{protocol:(d[z]||"")[C](),host:e[0],
port:e[1],path:e[2],Ia:d[ua]||"",url:a||""}}function Ma(a,b){function c(b,c){a.contains(b)||a.set(b,[]);a.get(b)[m](c)}for(var d=Ca(b)[x]("&"),e=0;e<d[v];e++)if(d[e]){var f=d[e][p]("=");0>f?c(d[e],"1"):c(d[e][A](0,f),d[e][A](f+1))}}function Oa(a,b){if(E(a)||"["==a[ka](0)&&"]"==a[ka](a[v]-1))return"-";var c=J.domain;return a[p](c+(b&&"/"!=b?b:""))==(0==a[p]("http://")?7:0==a[p]("https://")?8:0)?"0":a};var Pa=0;function Ra(a,b,c){!(1<=Pa)&&!(1<=100*l.random())&&(a=["utmt=error","utmerr="+a,"utmwv=5.2.9","utmn="+Da(),"utmsp=1"],b&&a[m]("api="+b),c&&a[m]("msg="+G(c[A](0,100))),L.A&&a[m]("aip=1"),Sa(a[B]("&")),Pa++)};var Ta=0,Ua={};function M(a){return Va("x"+Ta++,a)}function Va(a,b){Ua[a]=!!b;return a}
var N=M(),Wa=M(),Xa=M(),Ya=M(),Za=M(),O=M(),P=M(),$a=M(),ab=M(),bb=M(),cb=M(),db=M(),eb=M(),fb=M(),gb=M(),hb=M(),ib=M(),jb=M(),kb=M(),lb=M(),mb=M(),nb=M(),ob=M(),pb=M(),qb=M(),rb=M(),sb=M(),tb=M(),ub=M(),vb=M(),wb=M(),xb=M(),yb=M(),zb=M(),Ab=M(),Q=M(h),Bb=Va("page"),Cb=Va("title"),Db=M(),Eb=M(),Fb=M(),Gb=M(),Hb=M(),Ib=M(),Jb=M(),Kb=M(),Lb=M(),R=M(h),Mb=M(h),Nb=M(h),Qb=M(h),Rb=M(h),Sb=M(h),Tb=M(h),Ub=M(h),Vb=M(h),Wb=M(h),Xb=M(h),S=M(h),Yb=M(h),Zb=M(h),$b=M(h),ac=M(h),bc=M(h),cc=M(h),dc=M(h),ec=M(h),
fc=M(h),gc=M(h),hc=M(h),ic=M(h),jc=M(h),kc=Va("campaignParams"),lc=M(),mc=Va("hitCallback"),nc=M();M();var oc=M(),pc=M(),qc=M(),rc=M(),sc=M(),tc=M(),uc=M(),vc=M(),wc=M(),xc=M(),yc=M(),Cc=M();M();var Dc=M(),Ec=M(),Fc=M();var Ic=function(){function a(a,c,d){T(U[w],a,c,d)}Gc("_getName",Xa,58);Gc("_getAccount",N,64);Gc("_visitCode",R,54);Gc("_getClientInfo",fb,53,1);Gc("_getDetectTitle",ib,56,1);Gc("_getDetectFlash",gb,65,1);Gc("_getLocalGifPath",sb,57);Gc("_getServiceMode",tb,59);V("_setClientInfo",fb,66,2);V("_setAccount",N,3);V("_setNamespace",Wa,48);V("_setAllowLinker",cb,11,2);V("_setDetectFlash",gb,61,2);V("_setDetectTitle",ib,62,2);V("_setLocalGifPath",sb,46,0);V("_setLocalServerMode",tb,92,g,0);V("_setRemoteServerMode",
tb,63,g,1);V("_setLocalRemoteServerMode",tb,47,g,2);V("_setSampleRate",rb,45,1);V("_setCampaignTrack",hb,36,2);V("_setAllowAnchor",db,7,2);V("_setCampNameKey",kb,41);V("_setCampContentKey",pb,38);V("_setCampIdKey",jb,39);V("_setCampMediumKey",nb,40);V("_setCampNOKey",qb,42);V("_setCampSourceKey",mb,43);V("_setCampTermKey",ob,44);V("_setCampCIdKey",lb,37);V("_setCookiePath",P,9,0);V("_setMaxCustomVariables",ub,0,1);V("_setVisitorCookieTimeout",$a,28,1);V("_setSessionCookieTimeout",ab,26,1);V("_setCampaignCookieTimeout",
bb,29,1);V("_setReferrerOverride",Db,49);V("_setSiteSpeedSampleRate",wc,132);a("_trackPageview",U[w].ya,1);a("_trackEvent",U[w].D,4);a("_trackPageLoadTime",U[w].xa,100);a("_trackSocial",U[w].za,104);a("_trackTrans",U[w].Ba,18);a("_sendXEvent",U[w].t,78);a("_createEventTracker",U[w].ea,74);a("_getVersion",U[w].ja,60);a("_setDomainName",U[w].C,6);a("_setAllowHash",U[w].oa,8);a("_getLinkerUrl",U[w].ia,52);a("_link",U[w].link,101);a("_linkByPost",U[w].na,102);a("_setTrans",U[w].sa,20);a("_addTrans",U[w].Y,
21);a("_addItem",U[w].W,19);a("_setTransactionDelim",U[w].ta,82);a("_setCustomVar",U[w].pa,10);a("_deleteCustomVar",U[w].ga,35);a("_getVisitorCustomVar",U[w].ka,50);a("_setXKey",U[w].va,83);a("_setXValue",U[w].wa,84);a("_getXKey",U[w].la,76);a("_getXValue",U[w].ma,77);a("_clearXKey",U[w].ba,72);a("_clearXValue",U[w].ca,73);a("_createXObj",U[w].fa,75);a("_addIgnoredOrganic",U[w].U,15);a("_clearIgnoredOrganic",U[w].Z,97);a("_addIgnoredRef",U[w].V,31);a("_clearIgnoredRef",U[w].$,32);a("_addOrganic",
U[w].X,14);a("_clearOrganic",U[w].aa,70);a("_cookiePathCopy",U[w].da,30);a("_get",U[w].ha,106);a("_set",U[w].qa,107);a("_addEventListener",U[w].addEventListener,108);a("_removeEventListener",U[w].removeEventListener,109);a("_addDevId",U[w].T);a("_getPlugin",Hc,122);a("_setPageGroup",U[w].ra,126);a("_trackTiming",U[w].Aa,124);a("_initData",U[w].u,2);a("_setVar",U[w].ua,22);V("_setSessionTimeout",ab,27,3);V("_setCookieTimeout",bb,25,3);V("_setCookiePersistence",$a,24,1);a("_setAutoTrackOutbound",Ea,
79);a("_setTrackOutboundSubdomains",Ea,81);a("_setHrefExamineLimit",Ea,80)};function Hc(a){var b=this.plugins_;if(b)return b.get(a)}
var T=function(a,b,c,d){a[b]=function(){try{return d!=g&&H(d),c[xa](this,arguments)}catch(a){throw Ra("exc",b,a&&a[q]),a;}}},Gc=function(a,b,c,d){U[w][a]=function(){try{return H(c),za(this.a.get(b),d)}catch(e){throw Ra("exc",a,e&&e[q]),e;}}},V=function(a,b,c,d,e){U[w][a]=function(f){try{H(c),e==g?this.a.set(b,za(f,d)):this.a.set(b,e)}catch(j){throw Ra("exc",a,j&&j[q]),j;}}},Jc=function(a,b){return{type:b,target:a,stopPropagation:function(){throw"aborted";}}};var Kc=function(a,b){return"/"!==b?k:(0==a[p]("www.google.")||0==a[p](".google.")||0==a[p]("google."))&&!(-1<a[p]("google.org"))?h:k},Lc=function(a){var b=a.get(Za),c=a.c(P,"/");Kc(b,c)&&a[ra]()};var Qc=function(){var a={},b={},c=new Mc;this.j=function(a,b){c.add(a,b)};var d=new Mc;this.e=function(a,b){d.add(a,b)};var e=k,f=k,j=h;this.S=function(){e=h};this.i=function(a){this[ia]();this.set(lc,a,h);a=new Nc(this);e=k;d.execute(this);e=h;b={};this.n();a.Ca()};this.load=function(){e&&(e=k,this.Da(),Oc(this),f||(f=h,c.execute(this),Pc(this),Oc(this)),e=h)};this.n=function(){if(e)if(f)e=k,Pc(this),e=h;else this[ia]()};this.get=function(c){Ua[c]&&this[ia]();return b[c]!==g?b[c]:a[c]};this.set=
function(c,d,e){Ua[c]&&this[ia]();e?b[c]=d:a[c]=d;Ua[c]&&this.n()};this.v=function(b){a[b]=this.b(b,0)+1};this.b=function(a,b){var c=this.get(a);return c==g||""===c?b:1*c};this.c=function(a,b){var c=this.get(a);return c==g?b:c+""};this.Da=function(){if(j){var b=this.c(Za,""),c=this.c(P,"/");Kc(b,c)||(a[O]=a[eb]&&""!=b?F(b):1,j=k)}}};Qc[w].stopPropagation=function(){throw"aborted";};
var Nc=function(a){var b=this;this.q=0;var c=a.get(mc);this.Sa=function(){0<b.q&&c&&(b.q--,b.q||c())};this.Ca=function(){!b.q&&c&&ea(c,10)};a.set(nc,b,h)};function Rc(a,b){for(var b=b||[],c=0;c<b[v];c++){var d=b[c];if(""+a==d||0==d[p](a+"."))return d}return"-"}
var Tc=function(a,b,c){c=c?"":a.c(O,"1");b=b[x](".");if(6!==b[v]||Sc(b[0],c))return k;var c=1*b[1],d=1*b[2],e=1*b[3],f=1*b[4],b=1*b[5];if(!(0<=c&&0<d&&0<e&&0<f&&0<=b))return H(110),k;a.set(R,c);a.set(Rb,d);a.set(Sb,e);a.set(Tb,f);a.set(Ub,b);return h},Uc=function(a){var b=a.get(R),c=a.get(Rb),d=a.get(Sb),e=a.get(Tb),f=a.b(Ub,1);b==g?H(113):NaN==b&&H(114);0<=b&&0<c&&0<d&&0<e&&0<=f||H(115);return[a.b(O,1),b!=g?b:"-",c||"-",d||"-",e||"-",f][B](".")},Vc=function(a){return[a.b(O,1),a.b(Xb,0),a.b(S,1),
a.b(Yb,0)][B](".")},Wc=function(a,b,c){var c=c?"":a.c(O,"1"),d=b[x](".");if(4!==d[v]||Sc(d[0],c))d=i;a.set(Xb,d?1*d[1]:0);a.set(S,d?1*d[2]:10);a.set(Yb,d?1*d[3]:a.get(Ya));return d!=i||!Sc(b,c)},Xc=function(a,b){var c=G(a.c(Nb,"")),d=[],e=a.get(Q);if(!b&&e){for(var f=0;f<e[v];f++){var j=e[f];j&&1==j[ta]&&d[m](f+"="+G(j[q])+"="+G(j[la])+"=1")}0<d[v]&&(c+="|"+d[B]("^"))}return c?a.b(O,1)+"."+c:i},Yc=function(a,b,c){c=c?"":a.c(O,"1");b=b[x](".");if(2>b[v]||Sc(b[0],c))return k;b=b[ha](1)[B](".")[x]("|");
0<b[v]&&a.set(Nb,I(b[0]));if(1>=b[v])return h;b=b[1][x](-1==b[1][p](",")?"^":",");for(c=0;c<b[v];c++){var d=b[c][x]("=");if(4==d[v]){var e={};ga(e,I(d[1]));e.value=I(d[2]);e.scope=1;a.get(Q)[d[0]]=e}}return h},$c=function(a,b){var c=Zc(a,b);return c?[a.b(O,1),a.b(Zb,0),a.b($b,1),a.b(ac,1),c][B]("."):""},Zc=function(a){function b(b,e){if(!E(a.get(b))){var f=a.c(b,""),f=f[x](" ")[B]("%20"),f=f[x]("+")[B]("%20");c[m](e+"="+f)}}var c=[];b(cc,"utmcid");b(gc,"utmcsr");b(ec,"utmgclid");b(fc,"utmdclid");
b(dc,"utmccn");b(hc,"utmcmd");b(ic,"utmctr");b(jc,"utmcct");return c[B]("|")},bd=function(a,b,c){c=c?"":a.c(O,"1");b=b[x](".");if(5>b[v]||Sc(b[0],c))return a.set(Zb,g),a.set($b,g),a.set(ac,g),a.set(cc,g),a.set(dc,g),a.set(gc,g),a.set(hc,g),a.set(ic,g),a.set(jc,g),a.set(ec,g),a.set(fc,g),k;a.set(Zb,1*b[1]);a.set($b,1*b[2]);a.set(ac,1*b[3]);ad(a,b[ha](4)[B]("."));return h},ad=function(a,b){function c(a){return(a=b[ma](a+"=(.*?)(?:\\|utm|$)"))&&2==a[v]?a[1]:g}function d(b,c){c&&(c=e?I(c):c[x]("%20")[B](" "),
a.set(b,c))}-1==b[p]("=")&&(b=I(b));var e="2"==c("utmcvr");d(cc,c("utmcid"));d(dc,c("utmccn"));d(gc,c("utmcsr"));d(hc,c("utmcmd"));d(ic,c("utmctr"));d(jc,c("utmcct"));d(ec,c("utmgclid"));d(fc,c("utmdclid"))},Sc=function(a,b){return b?a!=b:!/^\d+$/.test(a)};var Mc=function(){this.B=[]};Mc[w].add=function(a,b){this.B[m]({name:a,r:b})};Mc[w].execute=function(a){try{for(var b=0;b<this.B[v];b++)this.B[b].r.call(W,a)}catch(c){}};function cd(a){100!=a.get(rb)&&a.get(R)%1E4>=100*a.get(rb)&&a[ra]()}function dd(a){ed(a.get(N))&&a[ra]()}function fd(a){"file:"==J[y][z]&&a[ra]()}function gd(a){a.get(Cb)||a.set(Cb,J.title,h);a.get(Bb)||a.set(Bb,J[y].pathname+J[y][ua],h)};var hd=new function(){var a=[];this.set=function(b){a[b]=h};this.Va=function(){for(var b=[],c=0;c<a[v];c++)a[c]&&(b[l[ja](c/6)]=b[l[ja](c/6)]^1<<c%6);for(c=0;c<b[v];c++)b[c]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"[ka](b[c]||0);return b[B]("")+"~"}};function H(a){hd.set(a)};var W=window,J=document,ed=function(a){var b=W._gaUserPrefs;return b&&b.ioo&&b.ioo()||!!a&&W["ga-disable-"+a]===h},id=function(a,b){ea(a,b)},jd=function(a){for(var b=[],c=J.cookie[x](";"),a=RegExp("^\\s*"+a+"=\\s*(.*?)\\s*$"),d=0;d<c[v];d++){var e=c[d][ma](a);e&&b[m](e[1])}return b},X=function(a,b,c,d,e,f){e=ed(e)?k:Kc(d,c)?k:h;if(e){if(b&&0<=W[ya].userAgent[p]("Firefox"))for(var b=b[n](/\n|\r/g," "),e=0,j=b[v];e<j;++e){var o=b.charCodeAt(e)&255;if(10==o||13==o)b=b[A](0,e)+"?"+b[A](e+1)}b&&2E3<b[v]&&
(b=b[A](0,2E3),H(69));a=a+"="+b+"; path="+c+"; ";f&&(a+="expires="+(new Date((new Date).getTime()+f)).toGMTString()+"; ");d&&(a+="domain="+d+";");J.cookie=a}};var kd,ld,md=function(){if(!kd){var a={},b=W[ya],c=W.screen;a.Q=c?c.width+"x"+c.height:"-";a.P=c?c.colorDepth+"-bit":"-";a.language=(b&&(b.language||b.browserLanguage)||"-")[C]();a.javaEnabled=b&&b.javaEnabled()?1:0;a.characterSet=J.characterSet||J.charset||"-";try{var d=J.documentElement,e=J.body,f=e&&e[qa]&&e[va],b=[];d&&(d[qa]&&d[va])&&("CSS1Compat"===J.compatMode||!f)?b=[d[qa],d[va]]:f&&(b=[e[qa],e[va]]);a.Ua=b[B]("x")}catch(j){H(135)}kd=a}},nd=function(){md();for(var a=kd,b=W[ya],a=b.appName+
b.version+a.language+b.platform+b.userAgent+a.javaEnabled+a.Q+a.P+(J.cookie?J.cookie:"")+(J.referrer?J.referrer:""),b=a[v],c=W.history[v];0<c;)a+=c--^b++;return F(a)},od=function(a){md();var b=kd;a.set(Fb,b.Q);a.set(Gb,b.P);a.set(Jb,b.language);a.set(Kb,b.characterSet);a.set(Hb,b.javaEnabled);a.set(Lb,b.Ua);if(a.get(fb)&&a.get(gb)){if(!(b=ld)){var c,d,e;d="ShockwaveFlash";if((b=(b=W[ya])?b.plugins:g)&&0<b[v])for(c=0;c<b[v]&&!e;c++)d=b[c],-1<d[q][p]("Shockwave Flash")&&(e=d.description[x]("Shockwave Flash ")[1]);
else{d=d+"."+d;try{c=new ActiveXObject(d+".7"),e=c.GetVariable("$version")}catch(f){}if(!e)try{c=new ActiveXObject(d+".6"),e="WIN 6,0,21,0",c.AllowScriptAccess="always",e=c.GetVariable("$version")}catch(j){}if(!e)try{c=new ActiveXObject(d),e=c.GetVariable("$version")}catch(o){}e&&(e=e[x](" ")[1][x](","),e=e[0]+"."+e[1]+" r"+e[2])}b=e?e:"-"}ld=b;a.set(Ib,ld)}else a.set(Ib,"-")};var pd=function(a){if(Aa(a))this.r=a;else{var b=a[0],c=b.lastIndexOf(":"),d=b.lastIndexOf(".");this.g=this.h=this.l="";-1==c&&-1==d?this.g=b:-1==c&&-1!=d?(this.h=b[A](0,d),this.g=b[A](d+1)):-1!=c&&-1==d?(this.l=b[A](0,c),this.g=b[A](c+1)):c>d?(this.h=b[A](0,d),this.l=b[A](d+1,c),this.g=b[A](c+1)):(this.h=b[A](0,d),this.g=b[A](d+1));this.k=a[ha](1);this.Fa=!this.l&&"_require"==this.g;this.H=!this.h&&!this.l&&"_provide"==this.g}},Y=function(){T(Y[w],"push",Y[w][m],5);T(Y[w],"_getPlugin",Hc,121);T(Y[w],
"_createAsyncTracker",Y[w].Qa,33);T(Y[w],"_getAsyncTracker",Y[w].Ra,34);this.G=new Ja;this.p=[]};D=Y[w];D.Ha=function(a,b,c){var d=this.G.get(a);if(!Aa(d))return k;b.plugins_=b.plugins_||new Ja;b.plugins_.set(a,new d(b,c||{}));return h};D.push=function(a){var b=Z.Ta[xa](this,arguments),b=Z.p.concat(b);for(Z.p=[];0<b[v]&&!Z.O(b[0])&&!(b.shift(),0<Z.p[v]););Z.p=Z.p.concat(b);return 0};D.Ta=function(a){for(var b=[],c=0;c<arguments[v];c++)try{var d=new pd(arguments[c]);d.H?this.O(d):b[m](d)}catch(e){}return b};
D.O=function(a){try{if(a.r)a.r[xa](W);else if(a.H)this.G.set(a.k[0],a.k[1]);else{var b="_gat"==a.h?L:"_gaq"==a.h?Z:L.w(a.h);if(a.Fa){if(!this.Ha(a.k[0],b,a.k[2])){if(!a.Ja){var c=Na(""+a.k[1]);var d=c[z],e=J[y][z];var f;if(f="https:"==d||d==e?h:"http:"!=d?k:"http:"==e){var j;a:{var o=Na(J[y][wa]);if(!(c.Ia||0<=c.url[p]("?")||0<=c[pa][p]("://")||c[t]==o[t]&&c[na]==o[na]))for(var r="http:"==c[z]?80:443,s=L.Ea,b=0;b<s[v];b++)if(c[t]==s[b][0]&&(c[na]||r)==(s[b][1]||r)&&0==c[pa][p](s[b][2])){j=h;break a}j=
k}f=j&&!ed()}f&&(a.Ja=Ha(c.url))}return h}}else a.l&&(b=b.plugins_.get(a.l)),b[a.g][xa](b,a.k)}}catch(Qa){}};D.Qa=function(a,b){return L.s(a,b||"")};D.Ra=function(a){return L.w(a)};var td=function(){function a(a,b,c,d){g==f[a]&&(f[a]={});g==f[a][b]&&(f[a][b]=[]);f[a][b][c]=d}function b(a,b,c){if(g!=f[a]&&g!=f[a][b])return f[a][b][c]}function c(a,b){if(g!=f[a]&&g!=f[a][b]){f[a][b]=g;var c=h,d;for(d=0;d<j[v];d++)if(g!=f[a][j[d]]){c=k;break}c&&(f[a]=g)}}function d(a){var b="",c=k,d,e;for(d=0;d<j[v];d++)if(e=a[j[d]],g!=e){c&&(b+=j[d]);for(var c=[],f=g,da=g,da=0;da<e[v];da++)if(g!=e[da]){f="";da!=Ob&&g==e[da-1]&&(f+=da[u]()+Qa);for(var sd=e[da],zc="",Pb=g,Ac=g,Bc=g,Pb=0;Pb<sd[v];Pb++)Ac=
sd[ka](Pb),Bc=sa[Ac],zc+=g!=Bc?Bc:Ac;f+=zc;c[m](f)}b+=o+c[B](s)+r;c=k}else c=h;return b}var e=this,f=[],j=["k","v"],o="(",r=")",s="*",Qa="!",sa={"'":"'0"};sa[r]="'1";sa[s]="'2";sa[Qa]="'3";var Ob=1;e.La=function(a){return g!=f[a]};e.z=function(){for(var a="",b=0;b<f[v];b++)g!=f[b]&&(a+=b[u]()+d(f[b]));return a};e.Ka=function(a){if(a==g)return e.z();for(var b=a.z(),c=0;c<f[v];c++)g!=f[c]&&!a.La(c)&&(b+=c[u]()+d(f[c]));return b};e.f=function(b,c,d){if(!qd(d))return k;a(b,"k",c,d);return h};e.o=function(b,
c,d){if(!rd(d))return k;a(b,"v",c,d[u]());return h};e.getKey=function(a,c){return b(a,"k",c)};e.L=function(a,c){return b(a,"v",c)};e.J=function(a){c(a,"k")};e.K=function(a){c(a,"v")};T(e,"_setKey",e.f,89);T(e,"_setValue",e.o,90);T(e,"_getKey",e.getKey,87);T(e,"_getValue",e.L,88);T(e,"_clearKey",e.J,85);T(e,"_clearValue",e.K,86)};function qd(a){return"string"==typeof a}function rd(a){return"number"!=typeof a&&(g==Number||!(a instanceof Number))||l.round(a)!=a||NaN==a||a==ba?k:h};var ud=function(a){var b=W.gaGlobal;a&&!b&&(W.gaGlobal=b={});return b},vd=function(){var a=ud(h).hid;a==i&&(a=Da(),ud(h).hid=a);return a},wd=function(a){a.set(Eb,vd());var b=ud();if(b&&b.dh==a.get(O)){var c=b.sid;c&&("0"==c&&H(112),a.set(Tb,c),a.get(Mb)&&a.set(Sb,c));b=b.vid;a.get(Mb)&&b&&(b=b[x]("."),1*b[1]||H(112),a.set(R,1*b[0]),a.set(Rb,1*b[1]))}};var xd,yd=function(a,b,c){var d=a.c(Za,""),e=a.c(P,"/"),f=a.b($a,0),a=a.c(N,"");X(b,c,e,d,a,f)},Pc=function(a){var b=a.c(Za,"");a.b(O,1);var c=a.c(P,"/"),d=a.c(N,"");X("__utma",Uc(a),c,b,d,a.get($a));X("__utmb",Vc(a),c,b,d,a.get(ab));X("__utmc",""+a.b(O,1),c,b,d);var e=$c(a,h);e?X("__utmz",e,c,b,d,a.get(bb)):X("__utmz","",c,b,"",-1);(e=Xc(a,k))?X("__utmv",e,c,b,d,a.get($a)):X("__utmv","",c,b,"",-1)},Oc=function(a){var b=a.b(O,1);if(!Tc(a,Rc(b,jd("__utma"))))return a.set(Qb,h),k;var c=!Wc(a,Rc(b,jd("__utmb")));
a.set(Wb,c);bd(a,Rc(b,jd("__utmz")));Yc(a,Rc(b,jd("__utmv")));xd=!c;return h},zd=function(a){!xd&&!(0<jd("__utmb")[v])&&(X("__utmd","1",a.c(P,"/"),a.c(Za,""),a.c(N,""),1E4),0==jd("__utmd")[v]&&a[ra]())};var Cd=function(a){a.get(R)==g?Ad(a):a.get(Qb)&&!a.get(Dc)?Ad(a):a.get(Wb)&&Bd(a)},Dd=function(a){a.get(bc)&&!a.get(Vb)&&(Bd(a),a.set($b,a.get(Ub)))},Ad=function(a){var b=a.get(Ya);a.set(Mb,h);a.set(R,Da()^nd(a)&2147483647);a.set(Nb,"");a.set(Rb,b);a.set(Sb,b);a.set(Tb,b);a.set(Ub,1);a.set(Vb,h);a.set(Xb,0);a.set(S,10);a.set(Yb,b);a.set(Q,[]);a.set(Qb,k);a.set(Wb,k)},Bd=function(a){a.set(Sb,a.get(Tb));a.set(Tb,a.get(Ya));a.v(Ub);a.set(Vb,h);a.set(Xb,0);a.set(S,10);a.set(Yb,a.get(Ya));a.set(Wb,k)};var Ed="daum:q,eniro:search_word,naver:query,pchome:q,images.google:q,google:q,yahoo:p,yahoo:q,msn:q,bing:q,aol:query,aol:q,lycos:q,lycos:query,ask:q,netscape:query,cnn:query,about:terms,mamma:q,voila:rdata,virgilio:qs,live:q,baidu:wd,alice:qs,yandex:text,najdi:q,seznam:q,rakuten:qt,biglobe:q,goo.ne:MT,wp:szukaj,onet:qt,yam:k,kvasir:q,ozu:q,terra:query,rambler:query,conduit:q,babylon:q,search-results:q,avg:q,comcast:q,incredimail:q,startsiden:q".split(","),Kd=function(a){if(a.get(hb)&&!a.get(Dc)){for(var b=
!E(a.get(cc))||!E(a.get(gc))||!E(a.get(ec))||!E(a.get(fc)),c={},d=0;d<Fd[v];d++){var e=Fd[d];c[e]=a.get(e)}(d=a.get(kc))?(H(149),e=new Ja,Ma(e,d),d=e):d=La(J[y][wa],a.get(db)).d;if(!("1"==Ia(d.get(a.get(qb)))&&b)&&(d=Gd(a,d)||Hd(a),!d&&(!b&&a.get(Vb))&&(Id(a,g,"(direct)",g,g,"(direct)","(none)",g,g),d=h),d))if(a.set(bc,Jd(a,c)),b="(direct)"==a.get(gc)&&"(direct)"==a.get(dc)&&"(none)"==a.get(hc),a.get(bc)||a.get(Vb)&&!b)a.set(Zb,a.get(Ya)),a.set($b,a.get(Ub)),a.v(ac)}},Gd=function(a,b){function c(c,
d){var d=d||"-",e=Ia(b.get(a.get(c)));return e&&"-"!=e?I(e):d}var d=Ia(b.get(a.get(jb)))||"-",e=Ia(b.get(a.get(mb)))||"-",f=Ia(b.get(a.get(lb)))||"-",j=Ia(b.get("dclid"))||"-",o=c(kb,"(not set)"),r=c(nb,"(not set)"),s=c(ob),Qa=c(pb);if(E(d)&&E(f)&&E(j)&&E(e))return k;var sa=!E(j)&&E(e),Ob=E(s);if(sa||Ob){var ca=Ld(a),ca=La(ca,h);if((ca=Md(a,ca))&&!E(ca[1]&&!ca[2]))sa&&(e=ca[0]),Ob&&(s=ca[1])}Id(a,d,e,f,j,o,r,s,Qa);return h},Hd=function(a){var b=Ld(a),c=La(b,h);if(!(b!=g&&b!=i&&""!=b&&"0"!=b&&"-"!=
b&&0<=b[p]("://"))||c&&-1<c[t][p]("google")&&c.d.contains("q")&&"cse"==c[pa])return k;if((b=Md(a,c))&&!b[2])return Id(a,g,b[0],g,g,"(organic)","organic",b[1],g),h;if(b||!a.get(Vb))return k;a:{for(var b=a.get(xb),d=Ka(c[t]),e=0;e<b[v];++e)if(-1<d[p](b[e])){a=k;break a}Id(a,g,d,g,g,"(referral)","referral",g,"/"+c[pa]);a=h}return a},Md=function(a,b){for(var c=a.get(vb),d=0;d<c[v];++d){var e=c[d][x](":");if(-1<b[t][p](e[0][C]())){var f=b.d.get(e[1]);if(f&&(f=K(f),!f&&-1<b[t][p]("google.")&&(f="(not provided)"),
!e[3]||-1<b.url[p](e[3]))){a:{for(var c=f,d=a.get(wb),c=I(c)[C](),j=0;j<d[v];++j)if(c==d[j]){c=h;break a}c=k}return[e[2]||e[0],f,c]}}}return i},Id=function(a,b,c,d,e,f,j,o,r){a.set(cc,b);a.set(gc,c);a.set(ec,d);a.set(fc,e);a.set(dc,f);a.set(hc,j);a.set(ic,o);a.set(jc,r)},Fd=[dc,cc,ec,fc,gc,hc,ic,jc],Jd=function(a,b){function c(a){a=(""+a)[x]("+")[B]("%20");return a=a[x](" ")[B]("%20")}function d(c){var d=""+(a.get(c)||""),c=""+(b[c]||"");return 0<d[v]&&d==c}if(d(ec)||d(fc))return H(131),k;for(var e=
0;e<Fd[v];e++){var f=Fd[e],j=b[f]||"-",f=a.get(f)||"-";if(c(j)!=c(f))return h}return k},Nd=RegExp(/^https:\/\/(www\.)?google(\.com?)?(\.[a-z]{2}t?)?\/?$/i),Ld=function(a){a=Oa(a.get(Db),a.get(P));try{if(Nd.test(a))return H(136),a+"?q="}catch(b){H(145)}return a};var Pd=function(a){Od(a,J[y][wa])?(a.set(Dc,h),H(12)):a.set(Dc,k)},Od=function(a,b){if(!a.get(cb))return k;var c=La(b,a.get(db)),d=K(c.d.get("__utma")),e=K(c.d.get("__utmb")),f=K(c.d.get("__utmc")),j=K(c.d.get("__utmx")),o=K(c.d.get("__utmz")),r=K(c.d.get("__utmv")),c=K(c.d.get("__utmk"));if(F(""+d+e+f+j+o+r)!=c){d=I(d);e=I(e);f=I(f);j=I(j);f=Qd(d+e+f+j,o,r,c);if(!f)return k;o=f[0];r=f[1]}if(!Tc(a,d,h))return k;Wc(a,e,h);bd(a,o,h);Yc(a,r,h);Rd(a,j,h);return h},Td=function(a,b,c){var d;d=Uc(a)||"-";
var e=Vc(a)||"-",f=""+a.b(O,1)||"-",j=Sd(a)||"-",o=$c(a,k)||"-",a=Xc(a,k)||"-",r=F(""+d+e+f+j+o+a),s=[];s[m]("__utma="+d);s[m]("__utmb="+e);s[m]("__utmc="+f);s[m]("__utmx="+j);s[m]("__utmz="+o);s[m]("__utmv="+a);s[m]("__utmk="+r);d=s[B]("&");if(!d)return b;e=b[p]("#");if(c)return 0>e?b+"#"+d:b+"&"+d;c="";f=b[p]("?");0<e&&(c=b[A](e),b=b[A](0,e));return 0>f?b+"?"+d+c:b+"&"+d+c},Qd=function(a,b,c,d){for(var e=0;3>e;e++){for(var f=0;3>f;f++){if(d==F(a+b+c))return H(127),[b,c];var j=b[n](/ /g,"%20"),o=
c[n](/ /g,"%20");if(d==F(a+j+o))return H(128),[j,o];j=j[n](/\+/g,"%20");o=o[n](/\+/g,"%20");if(d==F(a+j+o))return H(129),[j,o];try{var r=b[ma]("utmctr=(.*?)(?:\\|utm|$)");if(r&&2==r[v]&&(j=b[n](r[1],G(I(r[1]))),d==F(a+j+c)))return H(139),[j,c]}catch(s){}b=I(b)}c=I(c)}};var Ud="|",Wd=function(a,b,c,d,e,f,j,o,r){var s=Vd(a,b);s||(s={},a.get(yb)[m](s));s.id_=b;s.affiliation_=c;s.total_=d;s.tax_=e;s.shipping_=f;s.city_=j;s.state_=o;s.country_=r;s.items_=s.items_||[];return s},Xd=function(a,b,c,d,e,f,j){var a=Vd(a,b)||Wd(a,b,"",0,0,0,"","",""),o;a:{if(a&&a.items_){o=a.items_;for(var r=0;r<o[v];r++)if(o[r].sku_==c){o=o[r];break a}}o=i}r=o||{};r.transId_=b;r.sku_=c;r.name_=d;r.category_=e;r.price_=f;r.quantity_=j;o||a.items_[m](r);return r},Vd=function(a,b){for(var c=
a.get(yb),d=0;d<c[v];d++)if(c[d].id_==b)return c[d];return i};var Yd,Zd=function(a){if(!Yd){var b;b=J[y].hash;var c=W[q],d=/^#?gaso=([^&]*)/;if(c=(b=(b=b&&b[ma](d)||c&&c[ma](d))?b[1]:K(jd("GASO")))&&b[ma](/^(?:[|!]([-0-9a-z.]{1,40})[|!])?([-.\w]{10,1200})$/i))yd(a,"GASO",""+b),L._gasoDomain=a.get(Za),L._gasoCPath=a.get(P),a=c[1],Ha("https://www.google.com/analytics/web/inpage/pub/inpage.js?"+(a?"prefix="+a+"&":"")+Da(),"_gasojs");Yd=h}};var Rd=function(a,b,c){c&&(b=I(b));c=a.b(O,1);b=b[x](".");!(2>b[v])&&/^\d+$/.test(b[0])&&(b[0]=""+c,yd(a,"__utmx",b[B](".")))},Sd=function(a,b){var c=Rc(a.get(O),jd("__utmx"));"-"==c&&(c="");return b?G(c):c},$d=function(a){try{var b=La(J[y][wa],k),c=fa(Ia(b.d.get("utm_referrer")))||"";c&&a.set(Db,c);var d=fa(K(b.d.get("utm_expid")));d&&a.set(Fc,d)}catch(e){H(146)}};var ee=function(a,b){var c=l.min(a.b(wc,0),100);if(a.b(R,0)%100>=c)return k;c=ae()||be();if(c==g)return k;var d=c[0];if(d==g||d==ba||isNaN(d))return k;0<d?ce(c)?b(de(c)):b(de(c[ha](0,1))):Fa(W,"load",function(){ee(a,b)},k);return h},ge=function(a,b,c,d){var e=new td;e.f(14,90,b[A](0,64));e.f(14,91,a[A](0,64));e.f(14,92,""+fe(c));d!=g&&e.f(14,93,d[A](0,64));e.o(14,90,c);return e},ce=function(a){for(var b=1;b<a[v];b++)if(isNaN(a[b])||a[b]==ba||0>a[b])return k;return h},fe=function(a){return isNaN(a)||
0>a?0:5E3>a?10*l[ja](a/10):5E4>a?100*l[ja](a/100):41E5>a?1E3*l[ja](a/1E3):41E5},de=function(a){for(var b=new td,c=0;c<a[v];c++)b.f(14,c+1,""+fe(a[c])),b.o(14,c+1,a[c]);return b},ae=function(){var a=W.performance||W.webkitPerformance;if(a=a&&a.timing){var b=a.navigationStart;if(0==b)H(133);else return[a.loadEventStart-b,a.domainLookupEnd-a.domainLookupStart,a.connectEnd-a.connectStart,a.responseStart-a.requestStart,a.responseEnd-a.responseStart,a.fetchStart-b]}},be=function(){if(W.top==W){var a=W.external,
b=a&&a.onloadT;a&&!a.isValidLoadTime&&(b=g);2147483648<b&&(b=g);0<b&&a.setPageReadyTime();return b==g?g:[b]}};var U=function(a,b,c){function d(a){return function(b){if((b=b.get(Ec)[a])&&b[v])for(var c=Jc(e,a),d=0;d<b[v];d++)b[d].call(e,c)}}var e=this;this.a=new Qc;this.get=function(a){return this.a.get(a)};this.set=function(a,b,c){this.a.set(a,b,c)};this.set(N,b||"UA-XXXXX-X");this.set(Xa,a||"");this.set(Wa,c||"");this.set(Ya,l.round((new Date).getTime()/1E3));this.set(P,"/");this.set($a,63072E6);this.set(bb,15768E6);this.set(ab,18E5);this.set(cb,k);this.set(ub,50);this.set(db,k);this.set(eb,h);this.set(fb,
h);this.set(gb,h);this.set(hb,h);this.set(ib,h);this.set(kb,"utm_campaign");this.set(jb,"utm_id");this.set(lb,"gclid");this.set(mb,"utm_source");this.set(nb,"utm_medium");this.set(ob,"utm_term");this.set(pb,"utm_content");this.set(qb,"utm_nooverride");this.set(rb,100);this.set(wc,1);this.set(xc,k);this.set(sb,"/__utm.gif");this.set(tb,1);this.set(yb,[]);this.set(Q,[]);this.set(vb,Ed[ha](0));this.set(wb,[]);this.set(xb,[]);this.C("auto");this.set(Db,J.referrer);$d(this.a);this.set(Ec,{hit:[],load:[]});
this.a.j("0",Pd);this.a.j("1",Cd);this.a.j("2",Kd);this.a.j("3",Dd);this.a.j("4",d("load"));this.a.j("5",Zd);this.a.e("A",dd);this.a.e("B",fd);this.a.e("C",Cd);this.a.e("D",cd);this.a.e("E",Lc);this.a.e("F",he);this.a.e("G",zd);this.a.e("H",gd);this.a.e("I",od);this.a.e("J",wd);this.a.e("K",d("hit"));this.a.e("L",ie);this.a.e("M",je);0===this.get(Ya)&&H(111);this.a.S();this.F=g};D=U[w];D.m=function(){var a=this.get(zb);a||(a=new td,this.set(zb,a));return a};
D.Ga=function(a){for(var b in a){var c=a[b];a.hasOwnProperty(b)&&this.set(b,c,h)}};D.I=function(a){if(this.get(xc))return k;var b=this,c=ee(this.a,function(c){b.set(Bb,a,h);b.t(c)});this.set(xc,c);return c};D.ya=function(a){a&&Ba(a)?(H(13),this.set(Bb,a,h)):"object"===typeof a&&a!==i&&this.Ga(a);this.F=a=this.get(Bb);this.a.i("page");this.I(a)};
D.D=function(a,b,c,d,e){if(""==a||(!qd(a)||""==b||!qd(b))||c!=g&&!qd(c)||d!=g&&!rd(d))return k;this.set(pc,a,h);this.set(qc,b,h);this.set(rc,c,h);this.set(sc,d,h);this.set(oc,!!e,h);this.a.i("event");return h};D.Aa=function(a,b,c,d,e){var f=this.a.b(wc,0);1*e===e&&(f=e);if(this.a.b(R,0)%100>=f)return k;c=1*(""+c);if(""==a||(!qd(a)||""==b||!qd(b)||!rd(c)||isNaN(c)||0>c||0>f||100<f)||d!=g&&(""==d||!qd(d)))return k;this.t(ge(a,b,c,d));return h};
D.za=function(a,b,c,d){if(!a||!b)return k;this.set(tc,a,h);this.set(uc,b,h);this.set(vc,c||J[y][wa],h);d&&this.set(Bb,d,h);this.a.i("social");return h};D.xa=function(){this.set(wc,10);this.I(this.F)};D.Ba=function(){this.a.i("trans")};D.t=function(a){this.set(Ab,a,h);this.a.i("event")};D.ea=function(a){this.u();var b=this;return{_trackEvent:function(c,d,e){H(91);b.D(a,c,d,e)}}};D.ha=function(a){return this.get(a)};
D.qa=function(a,b){if(a)if(Ba(a))this.set(a,b);else if("object"==typeof a)for(var c in a)a.hasOwnProperty(c)&&this.set(c,a[c])};D.addEventListener=function(a,b){var c=this.get(Ec)[a];c&&c[m](b)};D.removeEventListener=function(a,b){for(var c=this.get(Ec)[a],d=0;c&&d<c[v];d++)if(c[d]==b){c.splice(d,1);break}};D.ja=function(){return"5.2.9"};D.C=function(a){this.get(eb);a="auto"==a?Ka(J.domain):!a||"-"==a||"none"==a?"":a[C]();this.set(Za,a)};D.oa=function(a){this.set(eb,!!a)};
D.ia=function(a,b){return Td(this.a,a,b)};D.link=function(a,b){if(this.a.get(cb)&&a){var c=Td(this.a,a,b);J[y].href=c}};D.na=function(a,b){this.a.get(cb)&&(a&&a.action)&&(a.action=Td(this.a,a.action,b))};
D.sa=function(){this.u();var a=this.a,b=J.getElementById?J.getElementById("utmtrans"):J.utmform&&J.utmform.utmtrans?J.utmform.utmtrans:i;if(b&&b[la]){a.set(yb,[]);for(var b=b[la][x]("UTM:"),c=0;c<b[v];c++){b[c]=Ca(b[c]);for(var d=b[c][x](Ud),e=0;e<d[v];e++)d[e]=Ca(d[e]);"T"==d[0]?Wd(a,d[1],d[2],d[3],d[4],d[5],d[6],d[7],d[8]):"I"==d[0]&&Xd(a,d[1],d[2],d[3],d[4],d[5],d[6])}}};D.Y=function(a,b,c,d,e,f,j,o){return Wd(this.a,a,b,c,d,e,f,j,o)};D.W=function(a,b,c,d,e,f){return Xd(this.a,a,b,c,d,e,f)};
D.ta=function(a){Ud=a||"|"};D.pa=function(a,b,c,d){var e=this.a;if(0>=a||a>e.get(ub))a=k;else if(!b||!c||128<b[v]+c[v])a=k;else{1!=d&&2!=d&&(d=3);var f={};ga(f,b);f.value=c;f.scope=d;e.get(Q)[a]=f;a=h}a&&this.a.n();return a};D.ga=function(a){this.a.get(Q)[a]=g;this.a.n()};D.ka=function(a){return(a=this.a.get(Q)[a])&&1==a[ta]?a[la]:g};D.va=function(a,b,c){this.m().f(a,b,c)};D.wa=function(a,b,c){this.m().o(a,b,c)};D.la=function(a,b){return this.m().getKey(a,b)};
D.ma=function(a,b){return this.m().L(a,b)};D.ba=function(a){this.m().J(a)};D.ca=function(a){this.m().K(a)};D.fa=function(){return new td};D.U=function(a){a&&this.get(wb)[m](a[C]())};D.Z=function(){this.set(wb,[])};D.V=function(a){a&&this.get(xb)[m](a[C]())};D.$=function(){this.set(xb,[])};D.X=function(a,b,c,d,e){if(a&&b){a=[a,b[C]()][B](":");if(d||e)a=[a,d,e][B](":");d=this.get(vb);d.splice(c?0:d[v],0,a)}};D.aa=function(){this.set(vb,[])};
D.da=function(a){this.a[ia]();var b=this.get(P),c=Sd(this.a);this.set(P,a);this.a.n();Rd(this.a,c);this.set(P,b)};D.ra=function(a,b){if(0<a&&5>=a&&Ba(b)&&""!=b){var c=this.get(yc)||[];c[a]=b;this.set(yc,c)}};D.T=function(a){a=""+a;if(a[ma](/^[A-Za-z0-9]{1,5}$/)){var b=this.get(Cc)||[];b[m](a);this.set(Cc,b)}};D.u=function(){this.a[ia]()};D.ua=function(a){a&&""!=a&&(this.set(Nb,a),this.a.i("var"))};var he=function(a){"trans"!==a.get(lc)&&500<=a.b(Xb,0)&&a[ra]();if("event"===a.get(lc)){var b=(new Date).getTime(),c=a.b(Yb,0),d=a.b(Tb,0),c=l[ja](1*((b-(c!=d?c:1E3*c))/1E3));0<c&&(a.set(Yb,b),a.set(S,l.min(10,a.b(S,0)+c)));0>=a.b(S,0)&&a[ra]()}},je=function(a){"event"===a.get(lc)&&a.set(S,l.max(0,a.b(S,10)-1))};var ke=function(){var a=[];this.add=function(b,c,d){d&&(c=G(""+c));a[m](b+"="+c)};this.toString=function(){return a[B]("&")}},le=function(a,b){(b||2!=a.get(tb))&&a.v(Xb)},me=function(a,b){b.add("utmwv","5.2.9");b.add("utms",a.get(Xb));b.add("utmn",Da());var c=J[y].hostname;E(c)||b.add("utmhn",c,h);c=a.get(rb);100!=c&&b.add("utmsp",c,h)},oe=function(a,b){b.add("utmac",Ca(a.get(N)));a.get(Fc)&&b.add("utmxkey",a.get(Fc),h);a.get(oc)&&b.add("utmni",1);var c=a.get(Cc);c&&0<c[v]&&b.add("utmdid",c[B]("."));
ne(a,b);L.A&&b.add("aip",1);b.add("utmu",hd.Va())},pe=function(a,b){for(var c=a.get(yc)||[],d=[],e=1;e<c[v];e++)c[e]&&d[m](e+":"+G(c[e][n](/%/g,"%25")[n](/:/g,"%3A")[n](/,/g,"%2C")));d[v]&&b.add("utmpg",d[B](","))},ne=function(a,b){function c(a,b){b&&d[m](a+"="+b+";")}var d=[];c("__utma",Uc(a));c("__utmz",$c(a,k));c("__utmv",Xc(a,h));c("__utmx",Sd(a));b.add("utmcc",d[B]("+"),h)},qe=function(a,b){a.get(fb)&&(b.add("utmcs",a.get(Kb),h),b.add("utmsr",a.get(Fb)),a.get(Lb)&&b.add("utmvp",a.get(Lb)),b.add("utmsc",
a.get(Gb)),b.add("utmul",a.get(Jb)),b.add("utmje",a.get(Hb)),b.add("utmfl",a.get(Ib),h))},re=function(a,b){a.get(ib)&&a.get(Cb)&&b.add("utmdt",a.get(Cb),h);b.add("utmhid",a.get(Eb));b.add("utmr",Oa(a.get(Db),a.get(P)),h);b.add("utmp",G(a.get(Bb),h),h)},se=function(a,b){for(var c=a.get(zb),d=a.get(Ab),e=a.get(Q)||[],f=0;f<e[v];f++){var j=e[f];j&&(c||(c=new td),c.f(8,f,j[q]),c.f(9,f,j[la]),3!=j[ta]&&c.f(11,f,""+j[ta]))}!E(a.get(pc))&&!E(a.get(qc),h)&&(c||(c=new td),c.f(5,1,a.get(pc)),c.f(5,2,a.get(qc)),
e=a.get(rc),e!=g&&c.f(5,3,e),e=a.get(sc),e!=g&&c.o(5,1,e));c?b.add("utme",c.Ka(d),h):d&&b.add("utme",d.z(),h)},te=function(a,b,c){var d=new ke;le(a,c);me(a,d);d.add("utmt","tran");d.add("utmtid",b.id_,h);d.add("utmtst",b.affiliation_,h);d.add("utmtto",b.total_,h);d.add("utmttx",b.tax_,h);d.add("utmtsp",b.shipping_,h);d.add("utmtci",b.city_,h);d.add("utmtrg",b.state_,h);d.add("utmtco",b.country_,h);c||(pe(a,d),oe(a,d));return d[u]()},ue=function(a,b,c){var d=new ke;le(a,c);me(a,d);d.add("utmt","item");
d.add("utmtid",b.transId_,h);d.add("utmipc",b.sku_,h);d.add("utmipn",b.name_,h);d.add("utmiva",b.category_,h);d.add("utmipr",b.price_,h);d.add("utmiqt",b.quantity_,h);c||(pe(a,d),oe(a,d));return d[u]()},ve=function(a,b){var c=a.get(lc);if("page"==c)c=new ke,le(a,b),me(a,c),se(a,c),qe(a,c),re(a,c),b||(pe(a,c),oe(a,c)),c=[c[u]()];else if("event"==c)c=new ke,le(a,b),me(a,c),c.add("utmt","event"),se(a,c),qe(a,c),re(a,c),b||(pe(a,c),oe(a,c)),c=[c[u]()];else if("var"==c)c=new ke,le(a,b),me(a,c),c.add("utmt",
"var"),!b&&oe(a,c),c=[c[u]()];else if("trans"==c)for(var c=[],d=a.get(yb),e=0;e<d[v];++e){c[m](te(a,d[e],b));for(var f=d[e].items_,j=0;j<f[v];++j)c[m](ue(a,f[j],b))}else"social"==c?b?c=[]:(c=new ke,le(a,b),me(a,c),c.add("utmt","social"),c.add("utmsn",a.get(tc),h),c.add("utmsa",a.get(uc),h),c.add("utmsid",a.get(vc),h),se(a,c),qe(a,c),re(a,c),pe(a,c),oe(a,c),c=[c[u]()]):c=[];return c},ie=function(a){var b,c=a.get(tb),d=a.get(nc),e=d&&d.Sa,f=0;if(0==c||2==c){var j=a.get(sb)+"?";b=ve(a,h);for(var o=0,
r=b[v];o<r;o++)Sa(b[o],e,j,h),f++}if(1==c||2==c){b=ve(a);o=0;for(r=b[v];o<r;o++)try{Sa(b[o],e),f++}catch(s){s&&Ra(s[q],g,s.message)}}d&&(d.q=f)};var we="https:"==J[y][z]?"https://ssl.google-analytics.com":"http://www.google-analytics.com",xe=function(a){ga(this,"len");this.message=a+"-8192"},ye=function(a){ga(this,"ff2post");this.message=a+"-2036"},Sa=function(a,b,c,d){b=b||Ea;if(d||2036>=a[v])ze(a,b,c);else if(8192>=a[v]){if(0<=W[ya].userAgent[p]("Firefox")&&![].reduce)throw new ye(a[v]);Ae(a,b)||Be(a,b)}else throw new xe(a[v]);},ze=function(a,b,c){var c=c||we+"/__utm.gif?",d=new Image(1,1);d.src=c+a;d.onload=function(){d.onload=i;d.onerror=
i;b()};d.onerror=function(){d.onload=i;d.onerror=i;b()}},Ae=function(a,b){var c,d=we+"/p/__utm.gif",e=W.XDomainRequest;if(e)c=new e,c.open("POST",d);else if(e=W.XMLHttpRequest)e=new e,"withCredentials"in e&&(c=e,c.open("POST",d,h),c.setRequestHeader("Content-Type","text/plain"));if(c)return c.onreadystatechange=function(){4==c.readyState&&(b(),c=i)},c.send(a),h},Be=function(a,b){if(J.body){a=aa(a);try{var c=J[oa]('<iframe name="'+a+'"></iframe>')}catch(d){c=J[oa]("iframe"),ga(c,a)}c.height="0";c.width=
"0";c.style.display="none";c.style.visibility="hidden";var e=J[y],e=we+"/u/post_iframe.html#"+aa(e[z]+"//"+e[t]+"/favicon.ico"),f=function(){c.src="";c.parentNode&&c.parentNode.removeChild(c)};Fa(W,"beforeunload",f);var j=k,o=0,r=function(){if(!j){try{if(9<o||c.contentWindow[y][t]==J[y][t]){j=h;f();Ga(W,"beforeunload",f);b();return}}catch(a){}o++;ea(r,200)}};Fa(c,"load",r);J.body.appendChild(c);c.src=e}else id(function(){Be(a,b)},100)};var $=function(){this.A=k;this.M={};this.N=[];this.Ma=0;this.Ea=[["www.google-analytics.com","","/plugins/"]];this._gasoCPath=this._gasoDomain=g;T($[w],"_createTracker",$[w].s,55);T($[w],"_getTracker",$[w].Oa,0);T($[w],"_getTrackerByName",$[w].w,51);T($[w],"_getTrackers",$[w].Pa,130);T($[w],"_anonymizeIp",$[w].Na,16);T($[w],"_getPlugin",Hc,120);Ic()};D=$[w];D.Oa=function(a,b){return this.s(a,g,b)};D.s=function(a,b,c){b&&H(23);c&&H(67);b==g&&(b="~"+L.Ma++);a=new U(b,a,c);L.M[b]=a;L.N[m](a);return a};
D.w=function(a){a=a||"";return L.M[a]||L.s(g,a)};D.Pa=function(){return L.N[ha](0)};D.Na=function(){this.A=h};var Ce=function(a){if("prerender"==J.webkitVisibilityState)return k;a();return h};var L=new $;var De=W._gat;De&&Aa(De._getTracker)?L=De:W._gat=L;var Z=new Y;(function(a){if(!Ce(a)){H(123);var b=k,c=function(){!b&&Ce(a)&&(b=h,Ga(J,"webkitvisibilitychange",c))};Fa(J,"webkitvisibilitychange",c)}})(function(){var a=W._gaq,b=k;if(a&&Aa(a[m])&&(b="[object Array]"==Object[w][u].call(Object(a)),!b)){Z=a;return}W._gaq=Z;b&&Z[m][xa](Z,a)});})();

